JotaiJotai

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

Family

atomFamily

参考: https://github.com/pmndrs/jotai/issues/23

使用方法

atomFamily(initializeAtom, areEqual): (param) => Atom

这将创建一个函数,该函数接受 param 并返回一个原子。 如果它已经被创建,它将从缓存中返回。 initializeAtom 是一个可以返回任何类型的原子(atom()atomWithDefault(),...)的函数。 注意 areEqual 是可选的,它告诉两个参数是否相等(默认为 Object.is)。

要复制 Recoil's atomFamily/selectorFamily 的类似行为, 请为 areEqual 指定一个 deepEqual 函数。例如:

import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'
import deepEqual from 'fast-deep-equal'
const fooFamily = atomFamily((param) => atom(param), deepEqual)

TypeScript

原子族的类型将从 initializeAtom 中推断出来。这是一个使用原始原子的典型用法。

import type { PrimitiveAtom } from 'jotai'
/**
* 这里的 atom(id) 返回一个 PrimitiveAtom<number>
* 而 PrimitiveAtom<number> 是一个 WritableAtom<number, SetStateAction<number>>
*/
const myFamily = atomFamily((id: number) => atom(id)).

你可以使用 TypeScript 泛型明确声明参数、值和原子的 setState 函数的类型。

atomFamily<Param, Value, Update>(initializeAtom: (param: Param) => WritableAtom<Value, Update>, areEqual?: (a: Param, b: Param) => boolean)
atomFamily<Param, Value>(initializeAtom: (param: Param) => Atom<Value>, areEqual?: (a: Param, b: Param) => boolean)

如果你想为原始原子明确声明 atomFamily,你需要使用 SetStateAction

type SetStateAction<Value> = Value | ((prev: Value) => Value)
const myFamily = atomFamily<number, number, SetStateAction<number>>(
(id: number) => atom(id),
)

注意:内存泄漏

在内部,atomFamily 只是一个 Map,其键是 param,其值是原子配置。 除非你明确地删除未使用的参数,否则这将导致内存泄漏。 如果你使用无限数量的参数,这是至关重要的。

有两种方法可以删除参数。

  • myFamily.remove(param) 允许你删除特定的参数。
  • myFamily.setShouldRemove(shouldRemove) 是注册 shouldRemove 函数,该函数立即运行并且当你要从缓存中获取原子时。
    • shouldRemove 是一个接受两个参数 createdAt(以毫秒为单位)和 param,并返回一个布尔值的函数。
    • 设置 null 将删除先前注册的函数。

示例

import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'
const todoFamily = atomFamily((name) => atom(name))
todoFamily('foo')
// 这将创建一个新的 atom('foo'),或者如果已经创建,则返回它
import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'
const todoFamily = atomFamily((name) =>
atom(
(get) => get(todosAtom)[name],
(get, set, arg) => {
const prev = get(todosAtom)
set(todosAtom, { ...prev, [name]: { ...prev[name], ...arg } })
},
),
)
import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'
const todoFamily = atomFamily(
({ id, name }) => atom({ name }),
(a, b) => a.id === b.id,
)

Codesandbox