diff --git a/docs/basics/primitives.mdx b/docs/basics/primitives.mdx index 29bb4f8897..9691d872ea 100644 --- a/docs/basics/primitives.mdx +++ b/docs/basics/primitives.mdx @@ -71,6 +71,7 @@ const Component = ({ value }) => { } ``` + ## useAtom The `useAtom` hook is to read an atom value in the state. @@ -95,6 +96,16 @@ The `updateValue` takes just one argument, which will be passed to the third argument of the write function of the atom. The behavior depends on how the write function is implemented. +**Note:** as mentioned in the *atom* section, you have to take care of handling the reference of your atom, otherwise it may enter an infinite loop +```typescript +const stableAtom = atom(0) +const Component = () => { + const [atomValue] = useAtom(atom(0)) // Will cause an infinite loop + const [atomValue] = useAtom(stableAtom) // is fine + const [derivedAtomValue] = useMemo(() => atom((get) => get(stableAtom) * 2), []) // is also fine +} +``` + ## Provider Provider is to provide state for a component sub tree. diff --git a/docs/utils/select-atom.mdx b/docs/utils/select-atom.mdx index d5b8938018..1b2044e9f4 100644 --- a/docs/utils/select-atom.mdx +++ b/docs/utils/select-atom.mdx @@ -53,6 +53,33 @@ const nameAtom = selectAtom(personAtom, (person) => person.name) const birthAtom = selectAtom(personAtom, (person) => person.birth, deepEquals) ``` +## Hold stable references + +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. + +```typescript +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: + +```typescript +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)) +} + +``` + ## CodeSandbox