Creating an atom family
Every atom we have created so far accepted no arguments. But what if we added some?
The active session data, the selected theme, the user settings, they all fit well into atoms. But how could we model a blog with multiple posts?
Ideally we would have a $post
atom that could be instantiated multiple times, for each blog post we need to access. Something like $post(postId)
.
Introducing atom families
An atom family is a function that accepts at least one argument.
Each unique set of arguments represents an individual atom.
Reago identifies each atom instance by serializing the provided arguments. For this reason, the argument types are restricted to the following primitives.
type AtomFamilyArg = string | number | boolean | null | undefined;
In the following code:
function $post(postId: number) {
return fetch(`/api/blog-post/${postId}`);
}
The $post
function is an atom family, while $post(4)
, $post(32)
and $post(123)
are examples of individual atoms.
Atoms in an atom family are completely independent of each other. They do not share state, actions nor dependencies.
Reading from an atom in a family
The read
function you are already familiar with optionally accepts extra arguments, representing an atom in the atom family.
Here is an example how you could read $post(42)
.
import {read} from 'reago';
function $post(postId) {
return fetch(`/api/blog-post/${postId}`);
}
const postPromise = read($post, 42);
Writing to an atom in a family
Similarly, the dispatch
function takes variable number of extra arguments too.
import {atomAction, atomState, dispatch, read} from 'reago';
function $atomFamily(atomId, initialValue) {
const [value, setValue] = atomState(initialValue);
atomAction(setValue, []);
return value;
}
dispatch($atomFamily, 'first-id', 0)(111);
dispatch($atomFamily, 'second-id', 0)(222);
assert(read($atomFamily, 'first-id', 0) === 111);
assert(read($atomFamily, 'second-id', 0) === 222);
assert(read($atomFamily, 'third-id', 333) === 333);
Solving the old mystery
You were probably wondering why dispatch(...)(...)
requires two function calls.
It is because the number of family arguments and the number of action arguments are both variable. They had to be separated.
Watching an atom in a family
It should be no surprise that watch
accepts extra arguments too.
import {watch} from 'reago';
function $atom(familyArg) {
// ...
}
watch($atom, 'family-arg', () => {
// ...
});
Invalidating an atom in a family
To invalidate a single atom in a family, call invalidate
with the extra family arguments.
import {invalidate} from 'reago';
function $post(postId) {
// ...
}
invalidate($post, 42);
Usage with frameworks
All of our official integrations support atom families too. Simply pass the family arguments as extra arguments after the atom reference itself.
For details, please refer to the API reference of the package you are using.