State management with Redux is really nice. But it can get convoluted really quickly. It's almost like a pub/sub may do the trick, but that's missing modules, immutability, etc. Well it's hybrid time!
- To manage state with a simple pub/sub pattern
- To improve upon the pub/sub with unidirectional data flow
- For State to return a new state (pure function)
- Message filtering can be applied without a
switchstatement (you create your own event$type) - To allow for manipulation of deeply nested state properties through use of strings
{'my[index]deeply.nests.state': 'new value'}(we're sending this to substate to not mutate the state, but make a new copy (Flux-y)! - Maintain a small size
- (if using modules)
import { myInstance } from 'myFile' - Components will register one or more methods to rerender themselves using your instance (see instantiation) using
myInstance.on('STATE_UPDATED', rerender)per method - Components take UI event ("click", "focus", etc) and pass it off to a Handler/Reducer
- The Handler/Reducer figures out what should change in the state (it does not update the state directly). It also figures out if/what
$typeshould be sent to the Pub/Sub module - The Handler/Reducer will then
emitUPDATE_STATEto the Pub/Sub module - The Pub/Sub module will create a new state and will
emitSTATE_UPDATEDor the specified$typeto the Components. - The Components will digest the new State using the method(s) registered in step 2
- If you want a deep clone pass in
$deep: trueinto the state on emit. ORdefaultDeep: truein the options.
npm install substate --save- copy and paste from
index.jsinto a<script>or external js file
substate is a class so you call it like so
myFile.js
import { substate } from 'substate';
Then you instantiate it as such
export const myInstance = new substate({options});
substate accepts an options object as an optional parameter. These are the possible options
| Option | Desc | Default |
|---|---|---|
| name | name of the instance | 'substateInstance' |
| currentState | index of state to start on | 0 |
| stateStorage | array of all the states | [ ] |
| state | object containing the initial state | null |
| defaultDeep | default to deep cloning the state everytime | false |
| beforeUpdate[ ] | array of middleware before state is updated.Has access to substate instance and action | [] |
| afterUpdate[ ] | array of middleware for after state is updated. Has access to substate instance | [] |
@paramoptional method parameter@param*required method parameter
| Method | Desc | Returns |
|---|---|---|
| getState | get a state @param* - index of state needed |
state |
| getcurrentState | get the current state | current state object |
| getProp | get a prop from current state @param* - string path to prop |
property you request |
| changeState | change the version of the state @param* - {requestedState: index of state, action: (optional name of event to emit)} |
emits action parameter event or 'STATE_CHANGED' event with the new current state |
| resetState | resets the stateStorage array to an empty array |
emits 'STATE_RESET' |
@paramoptional method parameter@param*required method parameter@param[num]order of method parameter
| Method | Desc |
|---|---|
| on | @param1* STRING of event name to listen to. @param2* FUNC handler to execute when this event you listen to happens |
| off | @param1* STRING of event name to remove handler from. @param2* FUNC to remove from the execution queue |
| emit | @param1* STRING event name @param2 object of data to pass into your handler event from 'on' method |
| Event | Desc | Returns |
|---|---|---|
| 'UPDATE_STATE' | updates the entire state with the object passed in | updated state |
| 'CHANGE_STATE' | fires changeState method requires requestedState as the index of the state you want. |
emits 'STATE_CHANGED' |
note: the object of data that is passed, cannot have a key called '$type'
| Method | Event | Custom Event | Next |
|---|---|---|---|
| emit | 'UPDATE_STATE' | @param2 is an object: {$type: 'MY_CUSTOM_EVENT'} |
Will update/change state. The $type property will then be emitted so you can listen to it like substateInstance.on('MY_CUSTOM_EVENT', func) |
Basically to utilitze a custom event, you still need to use UPDATE_STATE but the data object needs a $type with an event name you want the State to emit when updated
- better dev instructions and console warnings/errors
- seemless compatibility with infernojs, preactjs, stenciljs
- demos demos demos
- better documentation