{"id":13431300,"url":"https://github.com/mheiber/redux-machine","last_synced_at":"2025-04-05T10:10:39.671Z","repository":{"id":10852266,"uuid":"67256402","full_name":"mheiber/redux-machine","owner":"mheiber","description":"A tiny library (12 lines) for creating state machines in Redux apps","archived":false,"fork":false,"pushed_at":"2022-03-15T19:11:16.000Z","size":47,"stargazers_count":336,"open_issues_count":6,"forks_count":16,"subscribers_count":10,"default_branch":"dev","last_synced_at":"2024-10-16T01:44:13.359Z","etag":null,"topics":["javascript","reducer","redux","state-machine","state-management"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mheiber.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-02T21:36:39.000Z","updated_at":"2024-04-02T12:06:34.000Z","dependencies_parsed_at":"2022-08-07T06:00:42.941Z","dependency_job_id":null,"html_url":"https://github.com/mheiber/redux-machine","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mheiber%2Fredux-machine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mheiber%2Fredux-machine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mheiber%2Fredux-machine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mheiber%2Fredux-machine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mheiber","download_url":"https://codeload.github.com/mheiber/redux-machine/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247318745,"owners_count":20919484,"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":["javascript","reducer","redux","state-machine","state-management"],"created_at":"2024-07-31T02:01:02.051Z","updated_at":"2025-04-05T10:10:39.649Z","avatar_url":"https://github.com/mheiber.png","language":"JavaScript","readme":"# redux-machine\n\n![redux-machine](http://i63.tinypic.com/2igdbus_th.jpg)\n\n*A tiny lib (12 lines) for creating state machines as swappable Redux reducers*\n\n\u003e If you are using [Immutable JS](https://facebook.github.io/immutable-js/) in your stores, see [redux-machine-immutable](https://github.com/mheiber/redux-machine-immutable).\n\nredux-machine enables you to create [reducers](http://redux.js.org/docs/basics/Reducers.html) that can transition between different \"statuses.\" These are likes states in a [finite state machine](https://en.wikipedia.org/wiki/Finite-state_machine). The goal is for redux-machine to support complex workflows simply while keeping all state in the redux store. Keeping all state in the store is good because:\n\n- redux-machine works with time-travel debugging. Time-travel debugging was the main [motivation for building redux itself](https://www.youtube.com/watch?v=xsSnOQynTHs).\n- Debugging is easy because information is in one place (the store).\n- Statuses such are queryable by the user interface. This is helpful if you want to show things to the user such as loading spinners to indicate status\n\n## Install\n\n`npm install redux-machine --save`\n\n\u003e redux-machine internally uses Object.assign, which is an ES2015 feature. If you need to support older browsers, you can use a polyfill such as [core-js](https://github.com/zloirock/core-js#basic).\n\n## How to Use\n\nThis is the entire API for redux-machine:\n\n```js\n// entire API, no middleware required\nimport { createMachine } = from './index.js'\n\nconst fetchUsersReducer = createMachine({\n    'INIT': initReducer,\n    'IN_PROGRESS': inProgressReducer\n})\n```\n\nThe reducer returned by `createMachine` will act like `initReducer` when its status is `INIT` and will act like `inProgressReducer` when the status is `IN_PROGRESS`. If the store's `state.status` is undefined, the reducer for `INIT` is used (so it's a good idea to provide a reducer for the `INIT` status).\n\n`initReducer` and `inProgressReducer` can do status transitions by setting `state.status`:\n\n```js\nconst initReducer = (state = {error: null, users: []}, action) =\u003e {\n    switch (action.type) {\n    case 'FETCH_USERS':\n        return Object.assign({}, state, {\n            error: null,\n            // transition to a different status!\n            status: 'IN_PROGRESS'\n    })\n    default:\n        return state\n    }\n}\n\nconst inProgressReducer = (state = {}, action) =\u003e {\n    switch (action.type) {\n    case 'FETCH_USERS_RESPONSE':\n        return Object.assign({}, state, {\n            error: null,\n            users: action.payload.users,\n            // transition to a different status!\n            status: 'INIT'\n        })\n    case 'FETCH_USERS_FAIL':\n        return Object.assign({}, state, {\n            error: action.payload.error,\n            // transition to a different status!\n            status: 'INIT'\n        })\n    default:\n        return state\n    }\n}\n```\n\nThe example above defines the following state machine:\n\n![status machine for the api-calling example](http://oi67.tinypic.com/qz57qd.jpg)\n\nIn words:\n- When the status is `INIT` and the action type is `FETCH_USERS`, the machine transitions to `IN_PROGRESS` status.\n- When the status is `IN_PROGRESS` and the action type is `FETCH_USERS_RESPONSE` or `FETCH_USERS_FAIL`, the machine transitions to the `INIT` (initial) status.\n\n## Making Finite State Machine Reducers without a Library\n\nYou don't need redux-machine, since you can accomplish almost the same thing as in the example above by defining `fetchUsersReducer` as follows:\n\n```js\nconst fetchUsersReducer = (state, action) =\u003e {\n    switch (state.status) {\n    case 'INIT':\n        return initReducer(state, action)\n    case 'IN_PROGRESS':\n        return inProgressReducer(state, action)\n    default:\n        return initReducer(state, action)\n    }\n}\n```\n\nThe (marginal) advantages of using redux-machine over just using the FSM pattern is that you can more clearly express intent and write slightly less code.\n\n## Supporting an Extra Argument\n\nredux-machine supports to passing an extra argument to state reducers, for cases where a state reducer requires [a third argument for other state it depends on](https://github.com/reactjs/redux/blob/master/docs/faq/Reducers.md#how-do-i-share-state-between-two-reducers-do-i-have-to-use-combinereducers).\n\n## Asynchronous Effects\n\nredux-machine doesn't prescribe a way of handling asynchronous effects such as API calls. This leaves it open for you to use [no async effects library](http://stackoverflow.com/a/34599594/2482570), [redux-loop](https://github.com/redux-loop/redux-loop), [redux-thunk](https://github.com/gaearon/redux-thunk), [redux-saga](https://github.com/yelouafi/redux-saga), [redux-funk](https://github.com/mheiber/redux-funk) or [anything else](https://github.com/markerikson/redux-ecosystem-links/blob/master/side-effects.md).\n\n## Examples\n\nSee the [Redux Funk Examples repo](https://github.com/mheiber/redux-funk-examples) for examples using redux-machine and [redux-funk](https://github.com/mheiber/redux-funk):\n\n- [Shopping Cart Example](https://github.com/mheiber/redux-funk-examples/blob/master/examples/shopping-cart/src/reducers/cart.js#L62)\n\n- [Cancellable Counter Example](https://github.com/mheiber/redux-funk-examples/blob/master/examples/cancellable-counter/src/reducers/counter.js#L50)\n\nSee the [Redux Saga Examples](https://github.com/yelouafi/redux-saga/tree/master/examples) for comparison.\n","funding_links":[],"categories":["JavaScript","Libraries"],"sub_categories":["JavaScript"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmheiber%2Fredux-machine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmheiber%2Fredux-machine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmheiber%2Fredux-machine/lists"}