A tiny (~250 byte) utility to create state machine components using two pure functions.
This project uses node and npm. Go check them out if you don't have them locally installed.
npm install --save state-machine-component
Then with a module bundler like webpack or rollup, use as you would anything else:
import stateMachine from 'state-machine-component';
The UMD build is also available on unpkg:
<script src="//unpkg.com/state-machine-component/dist/state-machine-component.umd.js"></script>
The library will install itself globally as window.stateMachineComponent
.
The API is a single function that accepts 2 pure functions as arguments:
stateMachineComponent(reduce, render)
The first function, reduce()
, takes in the current state and applies an action
to it, similar to a reducer in Redux:
// Reduce is a redux-style reducer
function reduce(state, action) {
// actions are like Redux Standard Actions:
let { type, data, props } = action
return { } // just return the new state
}
The second function, render()
, is a pure functional component that gets passed the current state
instead of props
, and a second argument action()
- a function that creates a bound dispatcher for the given action type:
// Render is a functional component with little twist
function render(state, action) {
// action() creates a dispatcher for an action type:
return <button onClick={ action('TYPE') } />
}
// Remember:
// `state` is the current state.
// `action` is a redux standard action.
function reduce(state, action) {
switch (action.type) {
case '@@INIT': return { count: 0 }
case 'ADD': return { count: state.count+1 }
}
}
function render(state, action) {
return (
<div class="counter">
Current count: {state.count}
<button onClick={action('ADD')}>Add 1</button>
</div>
)
}
stateMachineComponent(reduce, render)
const ToDos = stateMachineComponent(
// (state, action)
({ todos, text }, { type, data, props }) => {
switch (type) {
case '@@INIT':return { todos: props.todos || [], text: '' };
case 'ADD': return { todos: todos.concat(text), text: '' };
case 'TEXT': return { text: data.target.value };
}
},
// state, action(type)
({ todos, text }, action) => (
<div>
<h2>State Machine ToDos</h2>
<ul>{todos.map( todo => <li>{todo}</li> )}</ul>
<form onSubmit={action('ADD')}>
<input value={text} onInput={action('TEXT')} />
</form>
</div>
)
);