JotaiJotai

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

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 함수에 의해 결정됩니다.
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를 추적합니다. year, month, day, hour, minute가 변경되면 업데이트됩니다.
// deepEquals를 사용하면 birth 필드가 동일한 데이터를 가진 새로운 객체로 교체되어도
// 이 아톰은 업데이트되지 않습니다. 예를 들어, 데이터베이스에서 person을 다시 읽어오는 경우입니다.
const birthAtom = selectAtom(personAtom, (person) => person.birth, deepEquals)

안정적인 참조 유지하기

렌더링 사이클에서 useAtom을 사용할 때 무한 루프를 방지하려면, 항상 useAtom에 안정적인 참조를 제공해야 합니다. selectAtom의 경우, 기본 atom선택자 모두 안정적이어야 합니다.

const [value] = useAtom(selectAtom(atom(0), (val) => val)) // 이렇게 하면 무한 루프가 발생합니다

이러한 제약 조건을 충족시키기 위해 여러 가지 방법이 있습니다:

const baseAtom = atom(0) // 안정적
const baseSelector = (v) => v // 안정적
const Component = () => {
// 해결책 1: "useMemo"를 사용해 전체 결과 atom을 메모이제이션
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))
}

Stackblitz