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))}