A tiny (265 byte) utility to create state machine components using two pure functions.
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>
)
);
Interesting.
I've been working on something very similar here (
conventional-component
) . However, my goal is to create a convention and library to create components once for React (or Preact) and then be able to hoist their state into whatever state management solution you wish. I have a working solution atm, but it's early days so I'm still improving the design.One thing which confuses me about this code is what is the
cache
doing? Is it some way of avoiding recreating action creators (and therefore re-renders)?