Development··6 min read

Zustand에서 Jotai로 갈아탄 이유

상태 관리 라이브러리를 마이그레이션한 이유와 과정, 그리고 달라진 점

Zustand가 싫어진 건 아니다

먼저 밝혀둘 게 있다. Zustand는 좋은 라이브러리다. 2년 넘게 잘 썼다. 심각한 문제가 있어서 바꾼 게 아니다. 근데 프로젝트가 커지면서 Zustand의 접근 방식이 안 맞기 시작한 부분이 생겼다.

그 불편함이 "한번 다른 거 써볼까?" 수준이었는데, 결국 전부 옮기게 됐다.

스토어가 뚱뚱해지는 게 문제였다

Zustand의 기본 패턴은 하나의 스토어에 관련 상태를 모으는 거다. useUserStore, useCartStore 이런 식. 처음엔 깔끔했다. 근데 기능이 추가될수록 스토어 하나가 상태를 스무 개, 서른 개씩 가지게 됐다.

useUserStore에 사용자 정보, 인증 토큰, 프로필 편집 상태, 알림 설정, 최근 검색어까지 들어갔다. 하나 바뀌어도 이 스토어를 구독하는 모든 컴포넌트가 리렌더링 대상이 됐다. selector로 필요한 것만 구독하면 되긴 하는데, 매번 신경 써야 하는 것 자체가 인지 부하였다. (selector 빼먹어서 생긴 성능 이슈를 잡은 적이 세 번은 있다.)

Jotai는 접근이 다르다

큰 스토어 대신 상태를 가장 작은 단위(atom)로 쪼갠다. userAtom, authTokenAtom, notificationSettingsAtom이 각각 독립적이다.

실제로 체감되는 건 리렌더링 범위다. 알림 설정이 바뀌어도 사용자 정보 구독 컴포넌트는 리렌더링 안 된다. selector 없이도 자동으로 세밀한 구독이 된다. 기본이 세밀한 구독이라는 게 Jotai를 고른 가장 큰 이유다.

파생 상태 만드는 게 우아하다

Zustand에서 파생 상태 만들려면 store 안에서 get() 쓰거나 selector에서 계산했다. Jotai에서는 atom((get) => get(cartAtom).length) 이렇게 atom을 조합해서 새 atom을 만든다. 장바구니 아이템 수, 총 가격, 할인 가격 같은 걸 각각 atom으로 만들면, 원본이 바뀔 때 의존하는 것만 재계산되고 그걸 구독하는 컴포넌트만 리렌더링. 이 자동 의존성 추적이 진짜 편하다.

마이그레이션은 3일 걸렸다

하루에 스토어 하나씩 atom으로 전환했다. 제일 시간 먹은 건 비동기 상태. Zustand에서는 action 안에서 async/await 쓰면 끝인데, Jotai는 비동기 atom이라는 별도 개념이 있다. atom(async (get) => { ... })로 비동기 데이터를 담는데 Suspense랑 연동되는 방식이 처음엔 낯설었다.

번들 크기는 의외의 수확

Zustand minified 약 3.5KB, Jotai 약 3.2KB. 큰 차이는 아닌데, Jotai가 쓰는 기능만 import하는 구조라 tree-shaking이 더 잘 된다. 실제 번들에서는 1KB 정도 더 작았다. 사용자 경험에 영향을 미치는 차이는 아니다. 근데 "작은 것부터 챙기자" 하는 마인드로. (이건 약간의 자기 합리화다.)

솔직히 아쉬운 점도 있다

DevTools가 Zustand보다 부실하다. Zustand는 Redux DevTools 연동이 잘 되어서 상태 변화를 시각적으로 추적할 수 있는데, Jotai DevTools는 아직 그 수준은 아니다.

그리고 atom이 너무 잘게 쪼개지면 파일이 많아진다. atoms/ 폴더에 atom 파일이 스물 몇 개 되니까 그것 나름의 관리 비용이 생겼다. 관련 atom들을 하나의 파일에 모아두는 컨벤션을 정해서 해결하긴 했는데, 처음에 이걸 안 정해놔서 나중에 정리하느라 시간 썼다.

뭘 쓸지는 프로젝트가 결정한다

둘 다 써본 입장에서 말하면. 상태 적고 단순하면 Zustand가 진입 장벽 낮아서 좋다. 상태 많고 의존성 복잡하면 Jotai의 atom 모델이 빛난다. "어떤 라이브러리가 좋냐"가 아니라 "내 프로젝트 상태 구조가 어떻게 생겼냐"에 따라 답이 달라진다. 도구를 프로젝트에 맞춰야지, 프로젝트를 도구에 맞추면 안 된다. 근데 이걸 알면서도 가끔 도구 먼저 고르는 실수를 한다. 사람이라서.

관련 글