@qiwi/cyclone
"State machine" for basic purposes.
Motivation
There're many redux-state-machine implementations. krasimir/stent is pretty good among others (just opinion). But:
Stent
does not allow to "lock" the execution thread. Therefore impossible to verify that next
step strictly follows (corresponds) by the prev
.- Has no standard mechanics for state rollback.
If these points are not significant for you, Stent
might be your best choice.
Features
- History-like api
- Lock mechanics
- Multi-step transition declarations
Typings
Typescript libdef typings/index.d.ts
is mounted by default.
Flowtype typings/index.flow.js
should be added manually to .flowconfig
lib section:
[lib]
./node_modules/@qiwi/cyclone/typings/
API
import {Machine} from '@qiwi/cyclone'
const handler1 = () => {}
const handler2 = () => {}
const opts = {
initialState: 'foo',
initialData: {a: 'AAA'},
transitions: {
'foo>bar': true,
'bar>baz': handler1,
'baz>foo': handler2,
'foo>bar>baz>foo': handler1
},
historySize: 5,
}
const machine = new Machine(opts)
current
Returns machine state digest:
machine.current()
next
Transits the machine to a new state:
machine.next('bar', {optional: 'args'}, 'for', 'handler')
machine.current()
prev
Reverts the last transition:
machine.current()
machine.prev()
machine.current()
lock
/ unlock
Prevents state update.
machine.lock('key')
machine.next('qux', {a: 'a'})
machine.unlock('invalidKey')
machine.unlock('key')
Usage examples
Imagine, Rematch model:
import txn from '../../../../api/txn'
import Machine from '@qiwi/cyclone'
const machine = new Machine({
initialState: 'init',
initialData: {},
transitions: {
'init>loading': true,
'loading>ok': (state, res) => res,
'loading>err': (state, res) => res,
'ok>loading': true,
'err>loading': true
}
})
export default {
state: machine.current(),
reducers: {
next(prev, next, ...payload) {
return machine.next(next, ...payload).current()
}
},
effects: {
async read (opts) {
this.next('loading')
const res = await txn.readList(opts)
this.next('ok', res)
}
}
}