외주 프로젝트에서 prop으로 전달하는 상태가 증가하기 시작해
클라이언트 상태 관리 라이브러리를 찾아보기 시작했습니다.
사용 경험이 없는 Recoil과 Zustand 두 후보를 추렸고,
그래도 React와 이름이 비슷한 Recoil을 선택해 프로젝트에 바로 적용했습니다.
1️⃣ 편하게 탑승하기엔 조금 부담스러웠던 Recoil
솔직히 처음엔 이름이 맘에 들어서 선택했는데요.
Redux처럼 store, reducer, action, action type, dispatch.. 등
몇 차례의 depth를 거치지 않고, atom과 selector라는
2가지 핵심 개념만을 사용해 상태 관리할 수 있단 점이
편리함으로 다가와 사용하고 싶었습니다.
// 간단한 count 예제. atom과 selector만 작성하면 된다!
import { atom, selector } from 'recoil';
import produce from 'immer';
interface ICount {
count: number;
}
export const countState = atom<ICount>({
key: 'countState',
default: { count: 0 },
});
export const countSelector = selector<number>({
key: 'countSelector',
get: ({ get }) => {
const state = get(countState);
return state.count;
},
set: ({ set }, newValue) => {
set(countState, produce((draft) => {
draft.count = newValue as number;
}));
},
});
atom과 selector를 별도의 모듈로 분리, 컴포넌트로 import 해 사용할 수 있었습니다.
import { useRecoilState } from 'recoil';
import { countSelector } from './state';
const Counter = () => {
const [count, setCount] = useRecoilState(countSelector);
const increment = () => setCount(count + 1);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default Counter;
기본 개념과 프로젝트에 구현하기까지 1시간이 채 걸리지 않았습니다.
여기까지만 보면 Recoil이 최고다, 역시 META 라고 말할 수 있겠죠.
하지만 저는 코드를 작성하면서 느낀 불편함과
구글링 도중, 크게 5가지의 이유를 들어 Zustand로 환승해야겠다는 생각이 들었는데요.
1. 예상했던 것 보다 많았던 recoil의 기능.
2. 너무 번거로웠던 key값 설정.
3. zustand보다 높은 JS 번들링 사이즈.
4. npm trends를 통한 개발자들의 zustand 다운로드 수.
5. recoil의 드문 업데이트(현시점 2023년 3월 1일이 마지막 업데이트).
특히 1번과 2번이 Zustand로 넘어가게 된 계기였는데요.
1-1) 예상했던 것 보다 많았던 recoil의 기능
tanstack-query를 사용하고 있어 굳이 recoil을 통해
Async Selectors까지 사용할 필요가 없었고,
다소 단순한 프로젝트이기에 useRecoilTransaction_UNSTABLE hook
이나 useRecoilCallback 등의 기능을 사용할 이유도 없었습니다.
기능 범위도 크고, react와의 궁합을 생각해 개발된 recoil이다 보니,
당연히 zustand보다 높은 번들링 사이즈를 가지는 것도 이해가 되었습니다.
1-2) 번거로운 key 설정
recoil로 상태 관리를 진행하다 보니 atom과 selector에
key 값을 부여하는 것이 피로감을 유발했습니다.
2️⃣ 푹신해서 탑승감 좋은 Zustand로 갈아타기
위에서 언급했던 Recoil의 단점을 Zustand에서 모두 보완했습니다.
전역 상태 크기가 메인 프로젝트에 비해 상당히 작아
기존에 진행했던 프로젝트 상태를 Zustand로 마이그레이션 하는 것은 어렵지 않았어요.
코드가 단순해져서 너무 편했습니다.
// state.ts
import { create } from 'zustand';
type State = {
count: number;
};
type Actions = {
setCount: (newTarget: number) => void;
};
const initialState: State = {
count: 0,
};
const useCountStore = create<State & Actions>((set) => ({
...initialState,
setCount: (newTarget: number) => set({ count: newTarget+1 }),
}));
export default useCountStore;
key 설정이 필요 없는 점이나 set 함수를 통한 상태의 부분 업데이트가 상당히 간편했습니다.
import useCountStore from './state';
const CounterComponent = () => {
const { count, setCount } = useCountStore();
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default CounterComponent;
3️⃣ 정리
새로 만들어 나갈 프로젝트라면 Zustand를 사용하는 것이 긍정적일거라 생각합니다.
사용 방법이 쉬워 누구와 협업하더라도 쉽게 환경에 적응해 프로젝트에 빠르게
투입될 수 있을테니까요!
번외로 Recoil은 발전 가능성이 보이지 않네요..
Reference
https://medium.com/@ian-white/recoil-vs-jotai-vs-zustand-09d3c8bd5bc0
Recoil vs Jotai vs Zustand
Recoil과 Jotai는 Context와 Provider, 그리고 훅을 기반으로 가능한 작은 상태를 효율적으로 관리하는데 초점을 맞춘다.
medium.com
https://recoiljs.org/ko/docs/guides/asynchronous-data-queries
비동기 데이터 쿼리 | Recoil
Recoil은 데이터 플로우 그래프를 통해 상태를 매핑하는 방법과 파생된 상태를 리액트 컴포넌트에 제공합니다. 가장 강력한 점은 graph에 속한 함수들도 비동기가 될 수 있다는 것입니다. 이는 비
recoiljs.org
'TIL' 카테고리의 다른 글
홈화면에 Server Driven UI를 적용해보았다 (0) | 2024.08.23 |
---|---|
개발 목표 중 하나인 결제 기능을 구현해보았다. (0) | 2024.08.08 |
도메인 지식은 선택이 아닌 "필수"다.(2024 AI EXPO) (0) | 2024.06.23 |
WebHoook으로 Github PR과 review 알림 자동화 적용기 (0) | 2024.05.21 |
일정 길이 이상의 텍스트에 ...을 붙이는 쉬운 방법 (0) | 2024.05.13 |