JotaiJotai

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

Select

selectAtom

⚠️ 尽管名为 selectAtom,但它被视为一种逃生舱。使用它意味着构建的原子模型不是100%纯粹的。优先使用派生原子,并仅在 equalityFnprevSlice 不可避免时使用 selectAtom

签名

function selectAtom<Value, Slice>(
anAtom: Atom<Value>,
selector: (v: Value, prevSlice?: Slice) => Slice,
equalityFn: (a: Slice, b: Slice) => boolean = Object.is,
): Atom<Slice>

此函数创建一个派生原子,其值是原始原子值的函数,由 selector 确定。 每当原始原子发生变化时,选择器函数就会运行;只有当 equalityFn 报告派生值已经改变时,它才更新派生原子。 默认情况下,equalityFn 是引用相等,但你可以提供你最喜欢的深度相等函数来在必要时稳定派生值。

示例

const defaultPerson = {
name: {
first: 'Jane',
last: 'Doe',
},
birth: {
year: 2000,
month: 'Jan',
day: 1,
time: {
hour: 1,
minute: 1,
},
},
}
// 原始原子。
const personAtom = atom(defaultPerson)
// 跟踪 person.name。当 person.name 对象发生变化时更新,即使
// name.first 和 name.last 实际上并未改变。
const nameAtom = selectAtom(personAtom, (person) => person.name)
// 跟踪 person.birth。当年、月、日、小时或分钟发生变化时更新。
// 使用 deepEquals 意味着如果 birth 字段被
// 替换为包含相同数据的新对象,此原子不会更新。例如,如果人重新
// 从数据库中读取。
const birthAtom = selectAtom(personAtom, (person) => person.birth, deepEquals)

保持稳定的引用

像往常一样,为了防止在渲染周期中使用 useAtom 时出现无限循环,你必须为 useAtom 提供原子的稳定引用。 对于 selectAtom,我们需要基础原子和选择器是稳定的。

const [value] = useAtom(selectAtom(atom(0), (val) => val)) // 这将导致无限循环

你有多种选择来满足这些约束:

const baseAtom = atom(0) // 稳定的
const baseSelector = (v) => v // 稳定的
const Component = () => {
// 解决方案 1:使用 "useMemo" 记忆整个结果原子
const [value] = useAtom(useMemo(() => selectAtom(baseAtom, (v) => v), []))
// 解决方案 2:使用 "useCallback" 记忆内联回调
const [value] = useAtom(
selectAtom(
baseAtom,
useCallback((v) => v, []),
),
)
// 解决方案 3:所有约束都已满足
const [value] = useAtom(selectAtom(baseAtom, baseSelector))
}

CodeSandbox