JotaiJotai

상태
React를 위한 기본적이고 유연한 상태 관리

Family

atomFamily

참조: https://github.com/pmndrs/jotai/issues/23

사용법

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

이 함수는 param을 받아서 아톰을 반환합니다.
만약 아톰이 이미 생성되었다면, 캐시에서 반환됩니다.
initializeAtom은 어떤 종류의 아톰(atom(), atomWithDefault(), ...)도 반환할 수 있는 함수입니다.
areEqual 인자는 선택 사항이며, 두 개의 파라미터가 같은지 비교합니다. 기본값은 Object.is입니다.

Recoil의 atomFamily/selectorFamily와 유사한 동작을 재현하려면,
areEqualdeepEqual 함수를 지정하면 됩니다. 예를 들어:

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

TypeScript

atom family의 타입은 initializeAtom에서 추론됩니다. 다음은 기본 원자(primitive atom)를 사용한 일반적인 예제입니다.

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)

기본 원자(primitive atom)에 대해 atomFamily를 명시적으로 선언하려면 SetStateAction을 사용해야 합니다.

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

주의: 메모리 누수

내부적으로 atomFamily는 키가 파라미터이고 값이 atom 설정인 Map입니다.
사용하지 않는 파라미터를 명시적으로 제거하지 않으면 메모리 누수가 발생할 수 있습니다.
이 문제는 무한한 수의 파라미터를 사용할 때 특히 중요합니다.

파라미터를 제거하는 방법은 두 가지가 있습니다.

  • myFamily.remove(param)을 사용하면 특정 파라미터를 제거할 수 있습니다.
  • myFamily.setShouldRemove(shouldRemove)shouldRemove 함수를 등록하는 방법입니다. 이 함수는 즉시 실행되며, 캐시에서 atom을 가져오려고 할 때도 실행됩니다.
    • shouldRemove는 밀리초 단위의 createdAtparam 두 가지 인자를 받고, 불리언 값을 반환하는 함수입니다.
    • null을 설정하면 이전에 등록된 함수가 제거됩니다.

예제

import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'
const todoFamily = atomFamily((name) => atom(name))
todoFamily('foo')
// 이 코드는 새로운 atom('foo')를 생성하거나, 이미 생성된 경우 해당 atom을 반환합니다.
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,
)

Stackblitz