UNPKG

redux-sigma

Version:

A state machine library for redux and redux-saga.

159 lines (111 loc) 5.32 kB
# redux-sigma <a href="https://moveax.it"><img alt="moveax" height="24px" src="https://github.com/moveaxlab/redux-sigma/raw/master/assets/by-moveax.png?raw=true" /></a> [![npm](https://img.shields.io/npm/v/redux-sigma)](https://www.npmjs.com/package/redux-sigma) [![Builds](https://img.shields.io/github/workflow/status/moveaxlab/redux-sigma/Test%20CI/master)](https://github.com/moveaxlab/redux-sigma/actions) [![Code coverage](https://img.shields.io/coveralls/github/moveaxlab/redux-sigma/master)](https://coveralls.io/github/moveaxlab/redux-sigma) `redux-sigma` is a library that allows implementation of state machines on top of `redux` and `redux-saga`. State machines implemented with `redux-sigma` react to events dispatched via `redux`, and their state can be stored inside `redux` using a dedicated reducer. The aim of `redux-sigma` is providing developers with a formal framework that can be used when dealing with complex business flows inside front-end applications. Being based on `redux-saga`, `redux-sigma` expects all your redux actions to follow the [FSA](https://github.com/redux-utilities/flux-standard-action) pattern. `redux-sigma` has extensive TypeScript support, and we recommend using it with TypeScript. You can read what features `redux-sigma` offers in the [docs](https://github.com/moveaxlab/redux-sigma/tree/master/docs), or you can start by reading the quick start below. If you want to look at a more detailed example, check out the [example](https://github.com/moveaxlab/redux-sigma/tree/master/example) folder. ## Installation ```bash $ yarn add redux-sigma ``` Assuming you are using `yarn`. `redux-sigma` has `redux` and `redux-saga` as peer dependencies. ## Quick Start State machines in `redux-sigma` must extend a generic `StateMachine` class. The simplest way to define a state machine is to extend the `StateMachine` class, and to define its abstract fields: ```typescript import { StateMachine } from 'redux-sigma'; class MyStateMachine extends StateMachine { initialState = 'first_state'; name = 'my_state_machine'; spec = { first_state: { transitions: { first_event: 'second_state', }, }, second_state: { transitions: { second_event: 'first_state', }, }, }; } ``` This state machine can be represented graphically as follows: ![A simple state machine](https://github.com/moveaxlab/redux-sigma/raw/master/assets/simple-state-machine.png?raw=true) The `spec` field is the actual _specification_ of the state machine: a high level description of what its states are, and how the state machine goes from one state to another. More on this [in the docs](https://github.com/moveaxlab/redux-sigma/tree/master/docs). The `initialState` field indicates what will be the state of the state machine when it first starts. The `name` field is what identifies state machines: for `redux-sigma`, two state machines cannot have the same name. ### Running your state machine To use a state machine, you first need to instantiate it: ```typescript export const myStateMachine = new MyStateMachine(); ``` Then, you must connect your state machine to `redux` via `redux-saga`. `redux-sigma` provides a `stateMachineStarterSaga` utility to coordinate state machines startup that integrates with your `redux` store and your `redux-saga` middleware. ```typescript import { createStore, applyMiddleware } from 'redux'; import { createSagaMiddleware } from 'redux-saga'; import { stateMachineStarterSaga } from 'redux-sigma'; import { rootReducer } from './root-reducer'; import { myStateMachine } from './my-state-machine'; const sagaMiddleware = createSagaMiddleware(); const store = createStore(rootReducer, applyMiddleware(sagaMiddleware)); sagaMiddleware.run(stateMachineStarterSaga, myStateMachine); ``` > Having more than one state machine with the same name > or two instances of the same state machine passed to `stateMachineStarterSaga` > will crash `redux-sigma`! State machines can be started and stopped by dispatching actions to `redux`: ```typescript store.dispatch(myStateMachine.start({})); store.dispatch(myStateMachine.stop()); ``` Multiple `start` actions dispatched one after another have no effect on the state machine: the state machine is started only once. The same is true for `stop` actions. To restart a running state machine, dispatch a `stop` action followed by a `start` action. ### Reading data from your state machine To have the state of your state machines available inside your `redux` store, use the `stateReducer` of the state machine: ```typescript import { combineReducers } from 'redux'; import { myStateMachine } from './my-state-machine'; const rootReducer = combineReducers({ my_state_machine: myStateMachine.stateReducer, }); ``` While the state machine is not running, its state will look like this: ```typescript console.log(store.getState().my_state_machine); // { state: null } ``` Once the state machine starts running, its state will look like this: ```typescript store.dispatch(myStateMachine.start({})); console.log(store.getState().my_state_machine); // { state: 'first_state', context: {} } ``` The state and context of the state machines will be updated independently during the state machine lifetime, according to its specification.