Reducer
Using reducers for complex state transitions in @ilokesto/state.
Reducer
For complex state transitions, @ilokesto/state supports a reducer-based mode similar to React's useReducer or Redux.
Defining a Reducer
A reducer is a pure function that takes the current state and an action, and returns the next state.
import { create } from '@ilokesto/state';
type State = { count: number };
type Action = { type: 'increment' } | { type: 'decrement' } | { type: 'set'; value: number };
const counterReducer = (state: State, action: Action): State => {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
case 'set': return { count: action.value };
default: return state;
}
};
const useCounter = create(counterReducer, { count: 0 });Dispatching Actions
In reducer mode, the hook returns a dispatch function instead of setState.
function Counter() {
const [count, dispatch] = useCounter(state => state.count);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}Global Dispatch
You can also use the writeOnly accessor to get the dispatch function outside of React.
export const incrementCount = () => {
const dispatch = useCounter.writeOnly();
dispatch({ type: 'increment' });
};Why Use Reducers?
- Complex Logic: When state transitions depend on multiple fields or require complex validation.
- Traceability: Reducers provide a clear path for all state changes, which is especially useful when combined with the
loggerordevtoolsmiddleware. - Interoperability: Easier to migrate existing
useReducerlogic to a global store.
Important Note
- No Partial Updates: Reducers must always return the full state object. Partial state updates are not supported in reducer mode.
- Middleware Integration: Reducer-based stores fully support all
@ilokesto/statemiddleware.