JotaiJotai

Jotai
React 原始而灵活的状态管理

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 依赖于 textAtomtextAtomuppercaseAtom 有依赖。所以,将 uppercaseAtom 添加到 textAtom 的依赖者中。 当我们重新运行读取函数(因为它的依赖项 textAtom 已更新)时, 依赖项会再次被创建,这在这种情况下是相同的。然后我们移除过时的依赖者并替换为最新的。

原子可以按需创建

虽然这里的基本示例显示在组件外部全局定义原子, 但我们可以在任何地方或任何时候创建原子。 只要我们记住原子是由它们的对象引用身份标识的, 我们可以随时创建它们。

如果你在渲染函数中创建原子,你通常会想使用 像 useRefuseMemo 这样的钩子进行记忆化。如果不这样做,每次组件渲染时原子都会被重新创建。

你可以创建一个原子并用 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 更新时导致不必要的重新渲染。