시작하며...
지금까지 다양한 프로젝트를 진행하면서 클라이언트에서 상태 관리를 간편하게 하기 위해 라이브러리를 사용하였다.
그중 Recoil, Zustand, Jotai 라이브러리를 사용해 보았고, 각기 다른 방식으로 상태 관리를 했다.
그래서 이번 글에서는 그동안 사용해 본 Recoil, Zustand, Jotai를 비교하고, 각 라이브러리를 어떤 상황에서 사용했고 느낀 장단점을 정리하게 되었다.
1. Recoil
1-1. 사용 배경
개발 동아리 DND 9기에서 진행한 NewPle 프로젝트에서 Recoil을 사용했다.
Recoil을 선택한 이유는 단순했다.
사실 React Query(TanStack Query)와 Recoil의 조합이 좋다는 이야기를 들어서 깊이 있는 이해 없이 그냥 선택하게 된 것이다.
(당시 나뿐만 아니라 함께 프로젝트를 진행한 프론트엔드 개발자도 경험이 많이 부족했다.)
(근데 실제로 서버에서 가져온 데이터를 처리하거나 하지 않음)
결론적으로 기능을 완전히 적용해보지 못해 아쉬웠지만, 프로젝트를 진행하며 Recoil 사용에 만족했고 잘 사용했다고 생각이 든다.
그러나 지금 쓰라고 하면 Recoil을 사용하는 것을 적극 찬성하지 않을 것 같다... 그 이유는 Recoil이 현재 지원 중단 이슈를 겪고 있기 때문에, 안정적인 서비스를 추구하거나 장기적인 관점에서는 적합하지 않다고 생각이 들기 때문이다. 🧐
1-2. 내가 사용한 방식
나는 Recoil을 두 곳에서 사용했다.
- 날짜 선택 관리
- 게시물 작성 내용 관리
[날짜 선택 관리]
현재 날짜를 계산해 Recoil 상태로 관리하는 방식을 사용했다.
날짜 데이터를 atom으로 생성하고, 초기값은 현재 날짜를 계산해 설정하는 방식이다.
getCurrentDate 함수를 통해 현재 날짜를 계산하고, 이를 Recoil의 DateState atom의 초기값으로 설정했다.
날짜는 YY-MM-DD 형태로 저장되며, 다양한 컴포넌트에서 전역적으로 접근할 수 있도록 관리했다.
상단바에서 사용자가 날짜를 선택하고, 바텀시트를 통해 그 날짜 데이터를 여러 컴포넌트에서 활용할 수 있어 작업이 효율적이었다.
그러나, 한 가지 아쉬운 점이 있었다. Recoil에 저장된 상태는 페이지를 새로고침하면 다시 초기화되어, 날짜가 현재 날짜로 돌아가게 되어 사용자 경험 측면에서 문제가 될 수 있다.
지금 돌아보면, 날짜 데이터를 URL의 쿼리 파라미터로 관리하는 방식이 더 적합했을 것이다. 쿼리 파라미터를 사용하면 새로고침을 하더라도 이전에 선택한 날짜가 유지되어 사용자 경험 측면에서 더 나은 결과를 줄 수 있기 때문이다.
[게시물 작성 내용 관리]
사용자가 게시물의 카테고리를 선택한 후, 글의 상세 내용을 작성하는 페이지로 이동하는 흐름을 구현했다.
이를 위해 Recoil을 사용하여 게시물 작성 데이터를 하나의 atom으로 관리했다.
이 코드는 postWriteState라는 atom을 사용해 게시물 작성 관련 모든 데이터를 전역 상태로 관리하고 있다.
예를 들어, 글 제목, 내용, 태그, 지역 등의 정보가 Recoil atom을 통해 저장되고, 여러 컴포넌트에서 쉽게 접근할 수 있었다.
하지만, 지금 돌아보니 이 방법은 비효율적이었다.........
폼의 각 필드가 업데이트될 때마다 전역 상태가 변경되면서 불필요한 리렌더링이 발생하기 때문이다.
그래서 해당 프로젝트 이후에는 React Hook Form의 FormProvider를 알게 되어 이를 적극 사용해 폼 데이터를 관리하는 방식으로 주로 사용하게 되었다.
이렇게 하면 폼 필드 업데이트가 전체 전역 상태에 영향을 주지 않으며, 리렌더링도 최소화되어 성능이 크게 개선되었다.
1-3. 장점
- 짧은 러닝 타임
- React 상태 관리에 최적화
- 비동기 데이터 관리
1-4. 단점
- 지원 중단
- 복잡한 구조 다룰 때 성능 저하
2. Zustand
2-1. 사용 배경
Zustand는 총 두 개의 프로젝트에서 사용한 경험이 있다.
"내 마음 속 바다" 프로젝트에서는 아쉽게도 개인적으로 Zustand를 사용할 일이 없었지만, 다행히 "wiki-viki" 프로젝트에서는 직접 활용해 볼 수 있었다.
두 프로젝트에서 Zustand를 선택한 이유는 비슷하다. 러닝 커브가 짧고, 자주 업데이트되며, 많은 사람들이 사용하는 라이브러리라는 점에서 안정성이 느껴졌기 때문이다.
이전과 달리, Zustand는 기능의 목적에 맞게 잘 사용할 수 있었고, 사용법도 직관적이어서 만족스러웠다.
그러나 한 가지 아쉬운 점은 Next.js와 함께 사용하면서 persist 기능을 적용했을 때 Hydration 에러가 발생한다는 점이다... (물론 해결은 가능함)
2-2. 내가 사용한 방식
- persist 사용하여 유저 정보 관리
[persist 사용하여 유저 정보 관리]
내가 상단 네비게이션 바 부분을 담당하게 되어, 로그인 여부를 전역 상태 관리를 하기 위해 Zustand를 사용하였다.
또한 유저의 정보를 매번 API 호출을 통해 가져오는 대신 로컬 스토리지를 사용하기 위해 persist 기능을 사용하여 로컬 스토리지에 저장하였다.
그래서 로그인할 때, 유저의 정보를 saveUser를 사용하여 저장하고 isLogin 값을 true로 변경한다.
그리고 상단 네비게이션 바에서 checkLogin을 사용하여 로그인 여부를 확인한다.
만약 로그아웃 버튼을 누르면 유저 정보를 null로 지우고 isLogin 값을 false로 변경하여 로그인 여부를 관리하였다.
개인적으로 잘 사용한 부분 같아서 이를 블로그 게시물로 따로 작성하였다.
2-3. 장점
- 짧은 러닝 타임
- 간단하고 직관적인 API
- 번들 사이즈가 가벼워 성능이 뛰어남
2-4. 단점
- Next.js에서 persist 사용할 경우 Hydration Error 발생
- 복잡한 구조 다룰 때 성능 저하
3. Jotai
3-1. 사용 배경
"우주윗미" 프로젝트에서 Jotai를 사용하였다.
Jotai를 선택한 이유는 우선 Zustand와 다르게 Next.js에 친화적이다.
실제 공식문서에도 Next.js 탭이 있을 정도이며, Hydration 에러가 발생하지 않을 거 같아 선택하게 되었다.
그리고 또한 팀원 모두 Jotai를 사용해 본 경험이 없어 학습적인 측면에서 사용해 보면 좋을 거 같아 선택하게 되었다.
또한 Zustand와 마찬가지로 러닝 커브가 짧고, 자주 업데이트되며, 많은 사람들이 사용하는 라이브러리이다.
3-2. 내가 사용한 방식
- 토스트 상태 관리
- 속한 팀 목록 정보 관리
[토스트 상태 관리]
해당 프로젝트에서 토스트 컴포넌트를 직접 구현하게 되었고, 토스트의 데이터를 전역적으로 상태 관리하기 위해 Jotai를 사용하였다.
사실 구현하면서 어려운 부분을 구현하다 보니 좀 힘들었지만, 그만큼 기능을 제대로 사용해 본 것 같아서 좋았다.
해당 내용이 복잡한 내용이라서 Jotai로 토스트를 구현한 과정에 대해 게시물로 자세히 작성하였다.
[속한 팀 목록 정보 관리]
단순하게 값을 저장하고 가져오는데 Jotai를 사용하는 것이 매우 간편하다.
상태값과 상태 업데이트 함수를 둘 다 가져올 땐 useAtom을, 생태값만 가져올 땐 useAtomValue를, 상태 업데이트 함수만 가져올 때는 useSetAtom을 사용하여 가져올 수 있다.
const [groupIdList, setGroupIdList] = useAtom(groupIdListAtom);
const groupIdList = useAtomValue(groupIdListAtom);
const setGroupIdList = useSetAtom(groupIdListAtom);
그래서 상황에 따라 적절한 훅을 사용하여 효율적으로 코드를 작성할 수 있게 된다.
간단하게 상태값 하나를 관리하는 경우 Jotai가 제일 간편하고 쉽게 사용할 수 있는 것 같다.
+) Codeit Resources 프로젝트에서 사용한 Jotai
코드잇 일경험 인턴에서 진행했던 프로젝트에서 Jotai를 선택하게 되었고, 그 중에서 나는 유저 관련 기능을 담당하게 되었다.
그래서 로그인을 하고 나서 로그인 여부, 유저 정보, ADMIN 여부를 persistence를 사용하여 간편하게 상태를 관리했다. 위에서 언급했던 것처럼 간단하게 상태값 하나를 관리하기 위해서는 Jotai가 제일 간편하고 쉬운 것 같다.
3-3. 장점
- 짧은 러닝 타임
- Atom 기반으로, 필요한 상태만 구독
- 간단하고 직관적인 API
3-4. 단점
- 상태가 복잡해질 경우 관리 어려움
- 타 라이브러리에 비해 커뮤니티가 작음
결론...
전역 상태 관리가 필요한 경우, React에 기본적으로 내장되어 있는 Context API도 선택할 수 있지만, 이게 실제로는 상태를 주입하는 방식이라 상태 변경 시마다 하위 컴포넌트까지 리렌더링되는 특성 때문에 성능 저하가 발생할 수 있다.
그래서 프로젝트 규모와 요구사항에 맞는 전역 상태 관리 라이브러리를 선택하는 것이 중요하다.
직접 사용해보았을 때, 작은 규모 프로젝트에서는 러닝 커브가 짧고 간편하게 사용할 수 있는 Jotai가 적합할 것 같고, 중간 규모에서는 사용법이 직관적인 Zustand를 선택할 것 같다.
여러 가지 라이브러리를 사용해 봄으로써 장단점을 이해하게 되었으며, 앞으로 라이브러리를 선택할 때 많은 도움이 될 것 같다.
'💜 리액트 > 라이브러리' 카테고리의 다른 글
useState 대신 TanStack Query로 옵티미스틱 업데이트 구현한 이유 (4) | 2024.10.09 |
---|---|
[Next.js] firebase 게시물 조회수 기능 구현 (생성, 조회, 갱신) (0) | 2024.08.29 |
[Tailwind] px 작성, 자동 rem 변환 (feat. pxr 단위) (0) | 2024.08.01 |
[Storybook] Next.js + Tailwind CSS + TypeScript 스토리북 적용하기 (0) | 2024.07.28 |
[에디터] React Quill 이미지 사이즈 조절 (quill-image-actions) (0) | 2024.07.02 |
FE 개발자가 되고 싶은 짱잼이
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!