atomFamily(options)
Returns a function that returns a writeable RecoilState
atom.
key
- A unique string used to identify the atom internally. This string should be unique with respect to other atoms and selectors in the entire application.default
- The initial value of the atom. It may either be a value directly, aRecoilValue
orPromise
that represents the default value, or a function to get the default value. The callback function is passed a copy of the parameter used when theatomFamily
function is called.
An atom
represents a piece of state with Recoil. An atom is created and registered per <RecoilRoot>
by your app. But, what if your state isn’t global? What if your state is associated with a particular instance of a control, or with a particular element? For example, maybe your app is a UI prototyping tool where the user can dynamically add elements and each element has state, such as its position. Ideally, each element would get its own atom of state. You could implement this yourself via a memoization pattern. But, Recoil provides this pattern for you with the atomFamily
utility. An Atom Family represents a collection of atoms. When you call atomFamily
it will return a function which provides the RecoilState
atom based on the parameters you pass in.
The atomFamily
essentially provides a map from the parameter to a atom. You only need to provide a single key for the atomFamily
and it will generate a unique key for each underlying atom. These atom keys can be used for persistence, and so must be stable across application executions. The parameters may also be generated at different callsites and we want equivalent parameters to use the same underlying atom. Therefore, value-equality is used instead of reference-equality for atomFamily
parameters. This imposes restrictions on the types which can be used for the parameter. atomFamily
accepts primitive types, or arrays or objects which can contain arrays, objects, or primitive types.
Example
An atomFamily()
takes almost the same options as a simple atom()
. However, the default value can also be parameterized. That means you could provide a function which takes the parameter value and returns the actual default value. For example:
or using selectorFamily
instead of selector
, you can also access the parameter value in a default
selector as well.
Subscriptions
One advantage of using this pattern for separate atoms for each element over trying to store a single atom with a map of state for all elements is that they all maintain their own individual subscriptions. So, updating the value for one element will only cause React components that have subscribed to just that atom to update.
Persistence
Persistence observers will persist the state for each parameter value as a distinct atom with a unique key based on serialization of the parameter value used. Therefore, it is important to only use parameters which are primitives or simple compound objects containing primitives. Custom classes or functions are not allowed.
It is allowed to “upgrade” a simple atom
to be an atomFamily
in a newer version of your app based on the same key. If you do this, then any persisted values with the old simple key can still be read and all parameter values of the new atomFamily
will default to the persisted state of the simple atom. If you change the format of the parameter in an atomFamily
, however, it will not automatically read the previous values that were persisted before the change. However, you can add logic in a default selector or validator to lookup values based on previous parameter formats. We hope to help automate this pattern in the future.