JotaiJotai

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

大对象

以下的例子和描述基于这个codesandbox,所以如果你在阅读这些例子的同时查看它,会有更好的理解。

有时我们需要在原子中存储嵌套数据,并且我们可能需要在不同的级别更改这些数据,或者我们需要使用部分数据而不监听所有的更改。

考虑这个例子:

const initialData = {
people: [
{
name: 'Luke Skywalker',
information: { height: 172 },
siblings: ['John Skywalker', 'Doe Skywalker'],
},
{
name: 'C-3PO',
information: { height: 167 },
siblings: ['John Doe', 'Doe John'],
},
],
films: [
{
title: 'A New Hope',
planets: ['Tatooine', 'Alderaan'],
},
{
title: 'The Empire Strikes Back',
planets: ['Hoth'],
},
],
info: {
tags: ['People', 'Films', 'Planets', 'Titles'],
},
}

focusAtom

focusAtom 创建一个新的原子,基于你传递给它的焦点。jotai-optics

我们使用这个工具来聚焦一个原子并从数据的特定部分创建一个原子。例如,我们可能需要消耗上述数据的 people 属性,这是我们如何做的:

import { atom } from 'jotai'
import { focusAtom } from 'jotai-optics'
const dataAtom = atom(initialData)
const peopleAtom = focusAtom(dataAtom, (optic) => optic.prop('people'))

focusAtom 返回 WritableAtom,这意味着可以更改 peopleAtom 数据。

如果我们更改上述数据示例的 films 属性,peopleAtom 不会导致重新渲染,这是使用 focusAtom 的好处之一。

splitAtom

当你想要为列表中的每个元素获取一个原子时,splitAtom 工具很有用。jotai/utils

我们使用这个工具来处理返回数组作为其值的原子。例如,我们上面创建的 peopleAtom 返回 people 属性数组,所以我们可以为该数组的每个项返回一个原子。如果数组原子是可写的,splitAtom 返回的原子将是可写的,如果数组原子是只读的,返回的原子也将是只读的。

import { splitAtom } from 'jotai/utils'
const peopleAtomsAtom = splitAtom(peopleAtom)

这就是我们在组件中如何使用它。

const People = () => {
const [peopleAtoms] = useAtom(peopleAtomsAtom)
return (
<div>
{peopleAtoms.map((personAtom) => (
<Person personAtom={personAtom} key={`${personAtom}`} />
))}
</div>
)
}

selectAtom

这个函数创建一个派生原子,其值是原始原子值的函数。jotai/utils

这个工具类似于 focusAtom,但我们在有一个只读原子时使用它来选择它的一部分,它总是返回一个只读原子。

假设我们想要消耗 info 数据,并且其数据总是不可更改的。我们可以从它创建一个只读原子并选择该创建的原子。

// 首先我们基于 initialData.info 创建一个只读原子
const readOnlyInfoAtom = atom((get) => get(dataAtom).info)

然后我们在我们的组件中使用它:

import { atom, useAtom } from 'jotai'
import { selectAtom, splitAtom } from 'jotai/utils'
const tagsSelector = (s) => s.tags
const Tags = () => {
const tagsAtom = selectAtom(readOnlyInfoAtom, tagsSelector)
const tagsAtomsAtom = splitAtom(tagsAtom)
const [tagAtoms] = useAtom(tagsAtomsAtom)
return (
<div>
{tagAtoms.map((tagAtom) => (
<Tag key={`${tagAtom}`} tagAtom={tagAtom} />
))}
</div>
)
}