title |
---|
selectAtom |
Ref: #36
function selectAtom<Value, Slice>(
anAtom: Atom<Value>,
selector: (v: Value) => Slice,
equalityFn: (a: Slice, b: Slice) => boolean = Object.is
): Atom<Slice>
This function creates a derived atom whose value is a function of the original atom's value,
determined by selector.
The selector function runs whenever the original atom changes; it updates the derived atom
only if equalityFn
reports that the derived value has changed.
By default, equalityFn
is reference equality, but you can supply your favorite deep-equals
function to stabilize the derived value where necessary.
const defaultPerson = {
name: {
first: 'Jane',
last: 'Doe',
},
birth: {
year: 2000,
month: 'Jan',
day: 1,
time: {
hour: 1,
minute: 1,
},
},
}
// Original atom.
const personAtom = atom(defaultPerson)
// Tracks person.name. Updated when person.name object changes, even
// if neither name.first nor name.last actually change.
const nameAtom = selectAtom(personAtom, (person) => person.name)
// Tracks person.birth. Updated when year, month, day, hour, or minute changes.
// Use of deepEquals means that this atom doesn't update if birth field is
// replaced with a new object containing the same data. E.g., if person is re-read
// from a database.
const birthAtom = selectAtom(personAtom, (person) => person.birth, deepEquals)
As always, to prevent an infinite loop when using useAtom
in render cycle, you must provide useAtom
a stable reference of your atoms.
For selectAtom
, we need both the base atom and the selector to be stable.
const [value] = useAtom(selectAtom(atom(0), (val) => val)) // So this will cause an infinite loop
You have multiple options in order to satisfy these constraints:
const baseAtom = atom(0) // Stable
const selector = (v) => v // Stable
const Component = () => {
// Solution 1: Memoize the whole resulting atom with "useMemo"
const [value] = useAtom(useMemo(() => selectAtom(baseAtom, (v) => v), []))
// Solution 2: Memoize the inline callback with "useCallback"
const [value] = useAtom(
selectAtom(
baseAtom,
useCallback((v) => v, [])
)
)
// Solution 3: All constraints are already satisfied
const [value] = useAtom(selectAtom(baseAtom, selector))
}