atomReducer
atomReducer is a hook that lets you add a reducer to your atom.
const [state, dispatch] = atomReducer(reducer, initialArg, init?)function atomReducer<Value, ActionArgs extends any[] = any[]>(
reducer: AtomReducerReducer<Value, ActionArgs>,
initialArg: Value,
init?: (initialArg: Value) => Value
): AtomReducer<Value, ActionArgs>
type AtomReducer<Value, ActionArgs extends any[] = any[]> =
[Value, AtomReducerDispatcher<ActionArgs>];
type AtomReducerReducer<Value, ActionArgs extends any[]> =
(prevState: Value, ...args: ActionArgs) => Value
type AtomReducerDispatcher<ActionArgs extends any[]> =
(...args: ActionArgs) => voidReference
atomReducer(reducer, initialArg, init?)
Call atomReducer at the top level of your atom to declare a state variable with a reducer.
import {atomReducer} from 'reago';
function $atom() {
const [counter, tick] = atomReducer(x => x + 1, 0);
}Parameters
reducer: The reducer function that specifies how the state gets updated. It must be pure, should take the state and any number of extra arguments, and should return the next state. State and action can be of any types.initialArg: The value from which the initial state is calculated. It can be a value of any type. How the initial state is calculated from it depends on the next init argument.init(optional): The initializer function that should return the initial state. If it is not specified, the initial state is set toinitialArg. Otherwise, the initial state is set to the result of callinginit(initialArg).
Returns
atomReducer returns an array with exactly two values.
- The current state. During the first computation, it is set to
init(initialArg)orinitialArg(if there is noinit). - The
dispatchfunction that lets you update the state to a different value and trigger a recomputation.
The returned array is immutable and is preserved between computations, as long as the state variable stays the same.
The dispatch function is stable and can be safely omitted from effect dependencies.
Caveats
atomReduceris a hook, so you can only call it at the top level of your atom. You cannot call it inside loops or conditions.
dispatch functions
The dispatch function returned by atomReducer lets you update the state to a different value and trigger a recomputation. It takes the exact same number of extra arguments as the reducer function you provided.
const [value, addProductOf] = atomReducer(
(prevValue, firstExtraArg, secondExtraArg) => prevValue + firstExtraArg * secondExtraArg,
0
);
addProductOf(1, 3); // value is now 3
addProductOf(2, 4); // value is now 3 + 2 * 4 = 11Parameters
...extraArgs: The optional arguments you defined in the providedreducerfunction. They can be of any type.
Returns
dispatch functions do not have a return value.
Caveats
- The
dispatchfunctions do not trigger recomputations immediately. Instead, the atom is invalidated and will be lazily recomputed on next read. - The
dispatchfunctions only update the variable for the next computation. If you read the destructured state variable right after calling thedispatchfunction, you will still see the old value. - If the new state you is identical to the previous state, as determined by an
Object.iscomparison, Reago will ignore it and avoid unnecessary recomputations. This is an optimization. - The
dispatchfunction is stable, so you will often see it omitted from effect dependencies. The function is guaranteed to stay the same across computations.
Examples
Counting how many times an atom was updated
Call atomReducer at the top-level of your atom to declare a state variable with a reducer that increases its value with each dispatch. Run the dispatch function on each action.
import {atomAction, atomReducer, atomState} from 'reago';
function $valueWithUpdateCounter() {
const [value, setValue] = atomState(0);
const [updateCounter, increaseUpdateCounter] = atomReducer(x => x + 1, 0);
atomAction((newValue) => {
setValue(newValue);
increaseUpdateCounter();
}, []);
return value;
}Using a custom init function
Pass a custom init function to the atomReducer to do extra processing on the initialArg.
import {atomReducer} from 'reago';
const doubleIt = x => x * 2;
function $atom() {
const [value, dispatch] = atomReducer(x => x + 1, 21, doubleIt);
// value starts at 42
}