JotaiJotai

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

在渲染时初始化状态

有时,你可能需要创建一个使用原子状态的可复用组件。

这些原子的初始状态由传递给组件的 props 决定。

下面是一个基本的示例,说明如何使用 Provider 及其 prop initialValues 来初始化状态。

基本示例

CodeSandbox 链接:codesandbox

考虑一个基本示例,你有一个可复用的 TextDisplay 组件,它允许你显示和更新纯文本。

这个组件有两个子组件,PrettyTextUpdateTextInput

  • PrettyText 以蓝色显示文本。
  • UpdateTextInput 是一个输入字段,它更新文本值。

你决定将 text 状态作为原子在组件之间共享,而不是在两个子组件中传递 text 作为 prop。

为了使 TextDisplay 组件可复用,我们接受一个 prop initialTextValue,它决定 text 原子的初始状态。

为了将 initialTextValuetextAtom 关联起来,我们将子组件包装在一个组件中,在该组件中我们创建一个新的存储并将其传递给 Provider 组件。

const textAtom = atom('')
const PrettyText = () => {
const [text] = useAtom(textAtom)
return (
<>
<text
style={{
color: 'blue',
}}
>
{text}
</text>
</>
)
}
const UpdateTextInput = () => {
const [text, setText] = useAtom(textAtom)
const handleInputChange = (e) => {
setText(e.target.value)
}
return (
<>
<input onChange={handleInputChange} value={text} />
</>
)
}
const HydrateAtoms = ({ initialValues, children }) => {
// 在这里使用 prop 在渲染时初始化状态
useHydrateAtoms(initialValues)
return children
}
export const TextDisplay = ({ initialTextValue }) => (
<Provider>
<HydrateAtoms initialValues={[[textAtom, initialTextValue]]}>
<PrettyText />
<br />
<UpdateTextInput />
</HydrateAtoms>
</Provider>
)

现在,我们可以轻松地复用 TextDisplay 组件,尽管它们引用的是"相同"的原子,但可以使用不同的初始文本值。

export default function App() {
return (
<div className="App">
<TextDisplay initialTextValue="initial text value 1" />
<TextDisplay initialTextValue="initial text value 2" />
</div>
)
}

这种行为是因为我们的子组件寻找最低的公共 Provider 祖先来获取其值。

有关 Provider 行为的更多信息,请阅读这里的文档。

对于更复杂的用例,请查看 Scope extension

使用 Typescript

useHydrateAtoms 有重载类型,typescript 无法从重载函数中提取类型。建议在将初始原子值传递给 useHydrateAtoms 时使用 Map

以下是一个工作示例:

import type { ReactNode } from 'react'
import { Provider, atom, useAtomValue } from 'jotai'
import type { WritableAtom } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'
const testAtom = atom('')
export default function App() {
return (
<Provider>
<AtomsHydrator atomValues={[[testAtom, 'hello']]}>
<Component />
</AtomsHydrator>
</Provider>
)
}
//这个组件包含所有的状态和逻辑
function Component() {
const testAtomValue = useAtomValue(testAtom)
return <div>{testAtomValue}</div>
}
function AtomsHydrator({
atomValues,
children,
}: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
atomValues: Iterable<
readonly [WritableAtom<unknown, [any], unknown>, unknown]
>
children: ReactNode
}) {
useHydrateAtoms(new Map(atomValues))
return children
}