현재 리엑트 생태계에서 가장 강력한 상태관리 툴은 Tanstack-Query라고 생각한다. 주로 서버상태로 비동기 상태관리에 특화되어있고 효율적으로 처리한다.
결과적으로 Tanstack Query도입 후 명확하게 필요한 "클라이언트 상태"는 매우 줄어들었고 ContextAPI만으로도 충분할 수 있지만. 그보다 더 단순하게 사용할 수 있는 Jotai를 써보자.
가장 기본으로 동기적 아톰이다. 매우 단순하다. 기본적으로 전역적으로 atom()이라는 상태를 만들고, useAtom()으로 호출하고 atom을 수정하는 등 useState훅처럼 사용할 수 있다.
const countAtom = atom(0) // atom생성, 초깃값지정, 전역상태
//countAtom.debugLabel = 'countAtom' // 디버깅 툴 전용 네이밍 용도
const App = () => {
const [count,setCount] = useAtom(countAtom)
return(
<>
<button onClick={() => setCount(count+1)}>{count}</button>
</>
)
}
비동기 작업을 처리하기 위한 아톰으로, 아톰은 비동기 함수로 정의되고 와 함께 로딩상태를 처리할 수도 있다.
비동기 아톰에서 기본적으로 'get'이라는 함수를 인자로 가진다. 아톰내에서 다른 아톰의 값을 읽을 수 있음
// pokeStore.ts
export const pageAtom = atom(0) // 동기 아톰
export const pokeListAtom = atom(async(get) => { // 비동기 아톰
const page = get(pageAtom)
const response = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=10offset=${page * 10}`)
const data = await response.json()
return data.results
})
// AsyncAtom.tsx
const PokeList = () => {
const [pokeList] = useAtom(pokeListAtom);
return <div>{JSON.stringify(pokeList)}</div>;
};
const AsyncAtom = () => {
const [page,setPage] = useAtom(pageAtom)
return (
<Suspense fallback='로딩중'> // 비동기 fallback
<PokeList />
<button onClick={()=> setPage(page + 1)}>+1</button>
</Suspense>
);
};
export default AsyncAtom;
아톰페밀리는 파라미터화된 아톰을 생성하기 위한 패턴, 동일한 구조의 여러개의 아톰을 필요에 따라 생성
const pageAtomFamily = atomFamily((page: string) => {
return atom(page);
});
const AtomFamily = () => {
const [params] = useSearchParams();
const [value] = useAtom(pageAtomFamily(params.get("page") || '0'));
return value;
};
export default AtomFamily;