JotaiJotai

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

Atoms in atom

atom()은 아톰 설정을 생성합니다. 이 설정은 객체이지만 값을 가지고 있지 않습니다.
아톰 설정은 문자열 키를 가지지 않으며, 참조 동등성(referential equality)으로 식별합니다.
다시 말해, 아톰 설정을 키처럼 사용할 수 있습니다.

atom 설정을 useState에 저장하기

먼저, atom 설정을 useState에 저장할 수 있습니다.

const Component = ({ atom1, atom2 }) => {
const [selectedAtom, setSelectedAtom] = useState(atom1)
const [value] = useAtom(selectedAtom)
return (
<div>
선택된 값: {value}
<button onClick={() => setSelectedAtom(atom1)}>atom 선택</button>
<button onClick={() => setSelectedAtom(atom2)}>
다른 atom 선택
</button>
</div>
)
}

atom 설정을 props로 전달할 수 있다는 점을 기억하세요.

이것이 의미가 없을 수도 있지만, 필요에 따라 atom 설정을 생성할 수도 있습니다.

const Component = () => {
const [currentAtom, setCurrentAtom] = useState(() => atom(0))
const [count, setCount] = useAtom(currentAtom)
return (
<div>
카운트: {count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
<button onClick={() => setCurrentAtom(atom(0))}>새로 생성</button>
</div>
)
}

atom 설정을 atom에 저장하기

마찬가지로, atom 설정을 다른 atom의 값으로 저장할 수 있습니다.

const firstNameAtom = atom('Tanjiro')
const lastNameAtom = atom('Kamado')
const showingNameAtom = atom(firstNameAtom)
const Component = () => {
const [nameAtom, setNameAtom] = useAtom(showingNameAtom)
const [name] = useAtom(nameAtom)
return (
<div>
Name: {name}
<button onClick={() => setNameAtom(firstNameAtom)}>
Show First Name
</button>
<button onClick={() => setNameAtom(lastNameAtom)}>Show Last Name</button>
</div>
)
}

파생된 atom을 생성할 수도 있습니다.

const derivedNameAtom = atom((get) => {
const nameAtom = get(showingNameAtom)
return get(nameAtom)
})
// 또는 더 짧은 버전
const derivedNameAtom = atom((get) => get(get(showingNameAtom)))

atom에 무엇이 들어있는지 혼동하지 않기 위해, atom에 명시적으로 이름을 붙이는 것이 중요합니다. 또한 TypeScript 타입 정보도 도움이 될 수 있습니다.

아톰 배열을 아톰에 저장하기

마지막으로, 아톰 내부에 아톰 패턴을 사용하여 아톰 설정 배열을 저장하는 방법이 있습니다.

const countsAtom = atom([atom(1), atom(2), atom(3)])
const Counter = ({ countAtom }) => {
const [count, setCount] = useAtom(countAtom)
return (
<div>
{count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
</div>
)
}
const Parent = () => {
const [counts, setCounts] = useAtom(countsAtom)
const addNewCount = () => {
const newAtom = atom(0)
setCounts((prev) => [...prev, newAtom])
}
return (
<div>
{counts.map((countAtom) => (
<Counter countAtom={countAtom} key={countAtom} />
))}
<button onClick={addNewCount}>Add</button>
</div>
)
}

이 방식의 장점은, 카운트를 증가시킬 때 해당하는 Counter 컴포넌트만 리렌더링되고 다른 컴포넌트는 리렌더링되지 않는다는 점입니다.

anAtom.toString()은 고유한 ID를 반환하며, 이는 map에서 key로 사용할 수 있습니다.

TypeScript 사용자를 위한 힌트

<Counter countAtom={countAtom} key={`${countAtom}`} />

아톰에 아톰 설정 맵 저장하기

마찬가지로, 배열 대신 객체 맵을 저장할 수 있습니다.

const pricesAtom = atom({
apple: atom(15),
orange: atom(12),
pineapple: atom(25),
})
const Fruit = ({ name, priceAtom }) => {
const [price] = useAtom(priceAtom)
return (
<div>
{name}: {price}
</div>
)
}
const Parent = () => {
const [prices] = useAtom(pricesAtom)
return (
<div>
{Object.keys(prices).map((name) => (
<Fruit name={name} priceAtom={prices[name]} key={name} />
))}
</div>
)
}