atomFamily
When you need to map a values to atoms, atomFamily comes in handy. It returns a memoized function that outputs atoms based on a given parameter (which must be serializable).
const atomFamily: <T, P extends SerializableParam>(
initialValue: T | ValueFromParam<T, P>,
options?: AtomFamilyOptions<T, P>,
) => (param: P) => Scoped<WritableState<T>>;
initialValue- The value used to initialize the atom. It can also be a function with the following signature:<T, P extends SerializableParam>(param: P) => T. This function form is useful when initializing atoms with different values based on the parameter.options?- Atom family configuration:tag?- A string identifier (seeatomfor details). Alternatively, it can be a function with the following signature:<P extends SerializableParam>(param: P) => string. The function form is useful when the tag should depend on the parameter.effects?- An array ofAtomEffect<T>.areValuesEqual?- A function that determines whether two consecutive values are equal (seeatomfor details).
info
Stan does not rely on referential equality for atomFamily parameters, so there's no need to maintain stable references. Cache keys are computed by serializing (stable stringification) the parameter values - hence the serializability requirement.
Example
Track score per userId:
const scores = atomFamily<number, string>(0);
Track score per User, starting from an initial value:
type User = {
id: string;
score: number;
};
const scores = atomFamily<number, User>(user => user.score);
Increase the score using React:
const Scoreboard: FC<{ user: User }> = ({ user }) => {
const [score, setScore] = useStan(scores(user));
return (
<>
<h1>{score}</h1>
<button onClick={() => setScore(prev => prev + 1)}>+</button>
</>
);
};