Select
selectAtom
⚠️ 尽管名为 selectAtom
,但它被视为一种逃生舱。使用它意味着构建的原子模型不是100%纯粹的。优先使用派生原子,并仅在 equalityFn
或 prevSlice
不可避免时使用 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))}