redux-sigma
Version:
A state machine library for redux and redux-saga.
159 lines (111 loc) • 5.32 kB
Markdown
# 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>
[](https://www.npmjs.com/package/redux-sigma)
[](https://github.com/moveaxlab/redux-sigma/actions)
[](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:

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.