{"id":20750188,"url":"https://github.com/mjstahl/use-state-machine","last_synced_at":"2026-02-28T05:04:05.761Z","repository":{"id":57388408,"uuid":"170550435","full_name":"mjstahl/use-state-machine","owner":"mjstahl","description":"Use Finite State Machines with React Hooks","archived":false,"fork":false,"pushed_at":"2019-09-10T13:36:47.000Z","size":107,"stargazers_count":27,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-21T10:55:51.105Z","etag":null,"topics":["finite-state-machine","fsm","javascript","react","react-hooks","state-machine","state-management"],"latest_commit_sha":null,"homepage":"https://npm.im/use-state-machine","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mjstahl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-13T17:34:27.000Z","updated_at":"2025-03-03T18:42:11.000Z","dependencies_parsed_at":"2022-09-09T15:42:45.672Z","dependency_job_id":null,"html_url":"https://github.com/mjstahl/use-state-machine","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjstahl%2Fuse-state-machine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjstahl%2Fuse-state-machine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjstahl%2Fuse-state-machine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjstahl%2Fuse-state-machine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mjstahl","download_url":"https://codeload.github.com/mjstahl/use-state-machine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251318857,"owners_count":21570419,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["finite-state-machine","fsm","javascript","react","react-hooks","state-machine","state-management"],"created_at":"2024-11-17T08:26:09.957Z","updated_at":"2026-02-28T05:04:00.712Z","avatar_url":"https://github.com/mjstahl.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![npm bundle size](https://img.shields.io/bundlephobia/minzip/use-state-machine.svg?color=success\u0026label=size) [![Build Status](https://travis-ci.com/mjstahl/use-state-machine.svg?branch=master)](https://travis-ci.com/mjstahl/use-state-machine) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-blue.svg)](https://standardjs.com)\n\n# use-state-machine\nUse Finite State Machines with React Hooks\n\n* [Installation](#installation)\n* [Example](#example)\n* [API](#api)\n* [Maintainers](#maintainers)\n* [License](#license)\n\n## Installation\n\n```console\n$ npm install --save use-state-machine\n```\n\n## Example\n\n```js\n// H2O.js\nimport React from 'react'\nimport { useStateMachine } from 'use-state-machine'\nimport H2OState from './H2O.state'\n\nfunction H2O () {\n  const [current, transition] = useStateMachine(H2OState)\n  return (\n    \u003cdiv\u003e\n      \u003cp\u003eYour H2O is in a {current.state} state.\u003c/p\u003e\n      \u003cp\u003eThe temperature of your H2O is {current.value}.\u003c/p\u003e\n      \u003cbutton\n        disabled={!transition.toLiquid}\n        onClick={() =\u003e transition.toLiquid()}\u003e\n        To Liquid\n      \u003c/button\u003e\n      \u003cbutton\n        disabled={!transition.toSolid}\n        onClick={() =\u003e transition.freeze()}\u003e\n        To Solid\n      \u003c/button\u003e\n      \u003cbutton\n        disabled={!transition.toGas}\n        onClick={() =\u003e transition.boil()}\u003e\n        To Gas\n      \u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n```js\n// H2O.state.js\nimport { StateMachine } from 'use-state-machine'\n\nexport default new StateMachine({\n  initial: 'liquid',\n  liquid: {\n    freeze: 'solid',\n    boil: 'gas',\n    value: '60F'\n  },\n  solid: {\n    melt: 'liquid',\n    value: '32F'\n  },\n  gas: {\n    chill: 'liquid'\n    value: '212F'\n  }\n})\n```\n\n## API\n\n### useStateMachine\n\n```js\nimport { useStateMachine } from 'use-state-machine'\n```\n\n**`useStateMachine(machine: Object | StateMachine) -\u003e [Object, Object]`**\n\n`useStateMachine` takes a JavaScript object or `StateMachine` Object as an argument and returns an array consisting of a `current` object and a `transition` object.\n\n\n**`current -\u003e Object`**\n\nThe `current` state consists of two properties: `state` and `value`.\n`state` returns the string representing the current state. `value` returns the value (object or primitive) of the current state if one exists and returns `undefined` if not.\n\n```js\nconst [ current ] = useStateMachine(H2OState)\n\ncurrent.state //-\u003e 'liquid'\ncurrent.value //-\u003e '60F'\n```\n\n**`transition -\u003e Object`**\n\n`transition` is an object with a collection of functions allowing the developer to avoid\ntransitioning using the string names. In the example above, when in the `liquid` state, two passive and two active functions exist on `transition`. The passive functions are `transition.toSolid`, `transition.toGas`. The two active functions are `transition.freeze` and `transition.boil`. All state specific functions on `transition` accept a single `value` argument.\n\nIf the value argument is an Object, the state's `value` and value argument will be merged. If the the state's `value` is not an Object, the state's `value` will be replaced with the value argument. If the state's `value` is a primitive and the value argument is an object, the state's `value` will be set to the value argument including a property named `value` set to the state's previous primitive value.\n\n```js\nconst [ current, transition ] = useStateMachine(H2OState)\ntransition.freeze()\n\ncurrent.state //-\u003e 'solid'\ncurrent.value //-\u003e '32F'\n\ntransition.melt()\n\ncurrent.state //-\u003e 'liquid'\n\ntransition.toGas()\n```\n\n### StateMachine\n\n```js\nimport { StateMachine } from 'use-state-machine'\n```\n\n**`new StateMachine(states: Object) -\u003e StateMachine`**\n\nTo create an instance of a StateMachine pass a 'states' object. A valid 'states' object must have, at a minimum, a single state. And an `initial` property which is set to a valid state property.\n\nThere are two types of `StateMachine` definitions: \"active\" and passive. If the definition includes names for each valid transition it is an \"active\" definition and the `transition` property will include \"active\" functions (like `freeze()` and `boild()`). An example of an \"active\" definition is:\n\n```js\nnew StateMachine({\n  initial: 'liquid',\n  liquid: {\n    freeze: 'solid',\n    boil: 'gas',\n    value: '60F'\n  },\n  solid: {\n    melt: 'liquid',\n    value: '32F'\n  },\n  gas: {\n    chill: 'liquid'\n    value: '212F'\n  }\n})\n```\n\nA \"passive\" definition uses the `to` property on each state indicating one or more valid states the current state can transition to. For a \"passive\" definition, the `transition` property will only include \"passive\" functions (like `toSolid` and `toGas`). An example of an \"passive\" definition is:\n\n```js\nnew StateMachine({\n  initial: 'liquid',\n  liquid: {\n    to: ['solid', 'gas']\n    value: '60F'\n  },\n  solid: {\n    to: 'liquid'\n    value: '32F'\n  },\n  gas: {\n    to: 'liquid'\n    value: '212F'\n  }\n})\n```\n\n\n**`\u003cStateMachine\u003e.state -\u003e String`**\n\nReturn the string name of the `StateMachine` state.\n\n\n**`\u003cStateMachine\u003e.value -\u003e Any`**\n\n`value` returns the value (object or primitive) of the current state if one exists and returns `undefined` if not.\n\n\n**`\u003cStateMachine\u003e.transition -\u003e Object`**\n\n`transition` is an object with a collection of functions allowing the developer to avoid\ntransitioning using the string names. In the example above, when in the `liquid` state, two passive and two active functions exist on `transition`. The passive functions are `transition.toSolid`, `transition.toGas`. The two active functions are `transition.freeze` and `transition.boil`. All state specific functions on `transition` accept a single `value` argument.\n\nIf the value argument is an Object, the state's `value` and value argument will be merged. If the the state's `value` is not an Object, the state's `value` will be replaced with the value argument. If the state's `value` is a primitive and the value argument is an object, the state's `value` will be set to the value argument including a property named `value` set to the state's previous primitive value.\n\n**`\u003cStateMachine\u003e.onTransition(callback: Function) -\u003e unsubscribe: Function`**\n\nWhen a `StateMachine` object transitions from one state to another all callbacks passed to the `onTransition` function are evaluated with the `StateMachine` object passed as the only argument to the callback. `onTransition` returns a function that unsubscribes the callback when executed.\n\n## Maintainers\n\n* Mark Stahl\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjstahl%2Fuse-state-machine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmjstahl%2Fuse-state-machine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjstahl%2Fuse-state-machine/lists"}