useAtom
useAtom
useAtom
钩子用于读取状态中的原子值。
状态可以被视为原子配置和原子值的 WeakMap。
useAtom
钩子返回原子值和更新函数作为元组,
就像 React 的 useState
一样。
它接受用 atom()
创建的原子配置。
最初,原子没有关联的值。
只有当通过 useAtom
使用原子时,
初始值才会存储在状态中。
如果原子是派生原子,读取函数被调用以计算初始值。
当一个原子不再被使用,意味着使用它的所有组件都被卸载,
并且原子配置不再存在,状态中的值就会被垃圾回收。
const [value, setValue] = useAtom(anAtom)
setValue
只接受一个参数,该参数将被传递
到原子的写函数的第三个参数。
行为取决于写函数如何实现。
注意:如在 原子 部分提到的,你必须处理好你的原子引用,否则可能会进入无限循环
const stableAtom = atom(0)const Component = () => {const [atomValue] = useAtom(atom(0)) // 这将导致无限循环const [atomValue] = useAtom(stableAtom) // 这是可以的const [derivedAtomValue] = useAtom(useMemo(// 这也是可以的() => atom((get) => get(stableAtom) * 2),[],),)}
注意:记住,React 负责调用你的组件。这意味着它必须是幂等的,准备好被多次调用。即使没有 props 或原子发生变化,你也经常会看到额外的重新渲染。没有提交的额外重新渲染是预 期的行为。这实际上是 React 18 中 useReducer 的默认行为。
签名
// 原始或可写的派生原子function useAtom<Value, Update>(atom: WritableAtom<Value, Update>,options?: { store?: Store },): [Value, SetAtom<Update>]// 只读原子function useAtom<Value>(atom: Atom<Value>,options?: { store?: Store },): [Value, never]
useAtom 钩子用于读取存储在 Provider 中的原子值。它返回原子值和更新函数作为元组,就像 useState 一样。它接受用 atom()
创建的原子配置。最初,Provider 中没有存储值。第一次通过 useAtom
使用原子时,它将在 Provider 中添加初始值。如果原子是派生原子,读取函数被执行以计算初始值。当一个原子不再被使用,意味着使用它的所有组件都被卸载,并且原子配置不再存在,值就会从 Provider 中移除。
const [value, setValue] = useAtom(anAtom)
setValue
接受一个参数,该参数将被传递到原子的 writeFunction 的第三个参数。行为取决于 writeFunction 如何实现。
原子依赖如何工作
首先,让我们解释一下。在当前的实现中,每次我们调用 "read" 函数,我们都会刷新依赖项和依赖者。例如,如果 A 依赖于 B,这意味着 B 是 A 的依赖项,A 是 B 的依赖者。
const uppercaseAtom = atom((get) => get(textAtom).toUpperCase())
读取函数是原子的第一个参数。
依赖项最初将为空。首次使用时,我们运行读取函数并知道 uppercaseAtom
依赖于 textAtom
。textAtom
对 uppercaseAtom
有依赖。所以,将 uppercaseAtom
添加到 textAtom
的依赖者中。
当我们重新运行读取函数(因为它的依赖项 textAtom
已更新)时,
依赖项会再次被创建,这在这种情况下是相同的。然后我们移除过时的依赖者并替换为最新的。
原子可以按需创建
虽然这里的基本示例显示在组件外部全局定义原子, 但我们可以在任何地方或任何时候创建原子。 只要我们记住原子是由它们的对象引用身份标识的, 我们可以随时创建它们。
如果你在渲染函数中创建原子,你通常会想使用
像 useRef
或 useMemo
这样的钩子进行记忆化。如果不这样做,每次组件渲染时原子都会被重新创建。
你可以创建一个原子并用 useState
或甚至在另一个原子中存储它。
在 issue #5 中看到一个例子。
检查 utils 中的 atomFamily
以获取参数化的原子。
useAtomValue
const countAtom = atom(0)const Counter = () => {const setCount = useSetAtom(countAtom)const count = useAtomValue(countAtom)return (<><div>count: {count}</div><button onClick={() => setCount(count + 1)}>+1</button></>)}
与 useSetAtom
钩子类似,useAtomValue
允许你访问只读原子。
useSetAtom
const switchAtom = atom(false)const SetTrueButton = () => {const setCount = useSetAtom(switchAtom)const setTrue = () => setCount(true)return (<div><button onClick={setTrue}>Set True</button></div>)}const SetFalseButton = () => {const setCount = useSetAtom(switchAtom)const setFalse = () => setCount(false)return (<div><button onClick={setFalse}>Set False</button></div>)}export default function App() {const state = useAtomValue(switchAtom)return (<div>State: <b>{state.toString()}</b><SetTrueButton /><SetFalseButton /></div>)}
如果你需要更新原子的值而不读取它,你可以使用 useSetAtom()
。
当性能是一个关注点时,这尤其有用,因为 const [, setValue] = useAtom(valueAtom)
会在每次 valueAtom
更新时导致不必要的重新渲染。