atomState
atomState is a hook that lets you add a state variable to your atom.
const [state, setState] = atomState(initialState)function atomState<Value>(
initialState: Value | (() => Value)
): AtomState<Value>
type AtomState<Value> =
[Value, AtomStateSetter<Value>];
type AtomStateSetter<Value> =
(nextState: AtomStateSetterNextState<Value>) => void;
type AtomStateSetterNextState<Value> =
Value | ((prevState: Value) => Value);Reference
atomState(initialState)
Call atomState at the top level of your atom to declare a state variable.
import {atomState} from 'reago';
function $atom() {
const [age, setAge] = atomState(29);
const [name, setName] = atomState('Anya');
const [todos, setTodos] = atomState(() => createTodos());
}The convention is to name state variables like [something, setSomething] using array destructuring.
Parameters
initialState: The value you want the state to be initially. It can be a value of any type, but there is a special behavior for functions. This argument is ignored after the initial computation.If you pass a function as
initialState, it will be treated as an initializer function. It should be pure, should take no arguments, and should return a value of any type. It will only run once, during the initial computation.
Returns
atomState returns an array with exactly two values.
- The current state. During the first computation, it will match the
initialStateyou have passed. - The
setfunction 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 set function is stable and can be safely omitted from effect dependencies.
Caveats
atomStateis a hook, so you can only call it at the top level of your atom. You cannot call it inside loops or conditions.
set functions, like setSomething(nextState)
The set function returned by atomState lets you update the state to a different value and trigger a lazy recomputation. You can pass the next state directly, or a function that calculates it from the previous state.
const [dish, setDish] = atomState('Pancake');
const [guests, setGuests] = atomState(2);
function updateState() {
setDish('Caviar');
setGuests(count => count + 1);
}Parameters
nextState: The value that you want the state to be. It can be a value of any type, but there is a special behavior for functions.If you pass a function as
nextState, it will be treated as an updater function. It must be pure, should take the current state as its only argument, and should return the next state.
Returns
set functions do not have a return value.
Caveats
- The
setfunctions do not trigger recomputations immediately. Instead, the atom is invalidated and will be lazily recomputed on next read. - The
setfunctions only update the variable for the next computation. If you read the destructured state variable right after calling thesetfunction, you will still see the old value. - If the new value you provide is identical to the current state, as determined by an
Object.iscomparison, Reago will ignore it and avoid unnecessary recomputations. This is an optimization. - If you are using an updater function, never try to modify the old value received through the args.
- The
setfunction is stable, so you will often see it omitted from effect dependencies. The function is guaranteed to stay the same across computations.
Examples
Adding state to an atom
Call atomState at the top-level of your atom to declare a state variable. Use actions or effects to mutate it.
import {atomAction, atomState, dispatch, read} from 'reago';
function $selectedDish() {
const [dish, setDish] = atomState('pancake');
atomAction(dish, []); // `setDish` is stable and does not have to be listed as a dependency
return dish;
}
assert(read($selectedDish) === 'pancake');
dispatch($selectedDish)('caviar');
assert(read($selectedDish) === 'caviar');Updating state based on the previous state
Call atomState at the top-level of your atom to declare a state variable. Use actions or effects to mutate it, but instead of passing a new value, pass a function that will mutate the old state.
import {atomComputationEffect, atomState} from 'reago';
function $increasingCounter() {
const [value, setValue] = atomState(0);
atomComputationEffect(() => {
const interval = setInterval(() => {
setValue(x => x + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return value;
}Remember to never mutate the old value in the set function updater.
// do not do this, ever
setObject(oldObject => {
oldObject.prop = 'new value';
return oldObject;
});
// create a new object instead
setObject(oldObject => ({
...oldObject,
prop: 'new value'
}));