🐻Zustand
Zustand가 가진 특징으로 가벼운 번들사이즈,
폭넓은 확장 가능성, provider가 없는 구조,
Flux패턴의 단방향 Pub/Sub 모델구조이다.
이러한 특징들로 요즘 대세 상태관리 라이브러리로
각광받고있다.
npm 공식 페이지에서 주간 다운로드 횟수를 보면
놀라운 주간 다운로드 횟수를 갱신중이다.
※ 2024-09-22 주요 상태관리 라이브러리 주간 다운로드 횟수
- Redux : 10,278,099
- Zustand : 4,243,907
- Redux-toolkit : 3,609,254
- Jotai : 1,177,983
- Recoil : 489,922
부동의 1위인 오리진 Redux를 제외한다면
Redux의 본체라 해도 무방한 Redux-toolkit 조차도 뛰어넘은
대세 상태관리 라이브러리이다.
이번 포스팅은 Zustand를 React에서 사용한다는 것을
기반으로 Zustand의 특징과 간단한 예제코드를
포스팅하고자 한다.
🪶가벼운 번들사이즈
Zustand는 획기적으로 가벼운 번들사이즈를 자랑한다.
고작 1.16kb의 사이즈 만으로 전체 상태를 용이하게
관리할 수 있어 프로젝트 자체의 용량을 더욱 가볍게
가져갈 수 있다.
🪝확장 가능성
redux와 같은 Flux패턴이기 때문에 redux의
reducer와 같은 개념으로 확장하여 유지보수성을
높일 수 있고 Zustand에서 제공하는 미들웨어를 통해
Redux dev-tools를 활용할 수 있어 디버깅에도
용이하게 확장이 가능하다.
🧺Provider가 없는 구조
이는 단순하게 생각하면 provider가 없어서 어쩌라고?
라는 생각이 들 수 있다. 하지만 React의 구조가 이를
엄청난 최적화요소로 만들어준다.
바로 Re-Render에 대한 최적화이다.
Provider로 감싸지 않는 구조로 상태 변화에 따른
불필요한 렌더링을 최소화 할 수 있게 되고
멀리보면 UX까지 영향을 끼칠 수 있는
핵심적인 요소라고 볼 수 있다.
📑Flux패턴의 구조
Flux패턴은 간단히 이야기 하자면 React와 Redux처럼
논리가 단방향으로 흐르는 아키텍처이며 대표적인 특징으로
디버깅이 쉽다는 특징을 가지고 있다.
- Flux 패턴 시각화
사용자 입력을 기반으로 Action을 만들고 Dispatcher에
전달한 후 Store의 데이터를 변경하고 View에 반영하여
단방향의 흐름으로 작동하며, View에서 State 변경이 감지되면
순서대로 재실행한다. 이러한 흐름을 통해 누락없이
변경된 State를 반영할 수 있다.
🔍Pub/Sub (발행/구독) 모델
Pub/Sub 모델은 Publish/Subscribe의 축약어로 메시지 기반의
미들웨어 시스템을 말하며, 메시지를 전송할 때 publisher(발행자)가
subscriber(구독자)에게 직접 메시지를 전송하지만 Pub/Sub 모델은
발행자(Pub)는 어떤 구독자(Sub)가 있는지 모르는 상태에서
메시지를 전송하고 구독자(Sub)는 발행자(Pub)에 대한 정보 없이
자신의 Interest(구독한 것)에 맞는 메시지만을 전송 받는 것을 의미한다.
즉, Zustand에서는 스토어의 상태 변경이 일어날 때 실행할
Listener 함수를 모아 두었다가(sub), 상태가 변경되었을 때
등록된 Listener 에게 상태가 변경되었다고 알려준다(pub).
🧑💻예제코드
간단한 예제코드로 Zustand의 미들웨어를 사용하여 Redux dev-tools를 활용가능한 코드이다.
import type {StoreApi, UseBoundStore} from "zustand";
import {create} from "zustand";
import {devtools} from "zustand/middleware";
export interface ITestObjState {
id: number;
title: string;
content: string;
}
export interface ITestStore {
testState: string;
testObjState: ITestObjState;
setTestState: (payload: string) => void;
setTestObjState: (payload: ITestObjState) => void;
}
export const useTestStore: UseBoundStore<StoreApi<ITestStore>> = create(
devtools((setState, getState, store) => ({
testState: "default value",
testObjState: {id: 0, title: "title", content: ""},
setTestState: (payload: string) => setState({testState: payload}),
setTestObjState: (payload: ITestObjState) => setState({testObjState: payload}),
})),
);
위 예제코드처럼 단순하게 devtools를 감싸주기만 하면 Redux dev-tools를 활용하여 디버깅이 가능해진다.
✍️마치며...
기존에 Redux로 상태관리 라이브러리를 입문했지만, Zustand를 접하고 나서부터는 Redux를 거의 사용하지 않았던 것 같다. 그 만큼 DX가 좋은 라이브러리라고 생각이 들었고 대세 라이브러리로 부상한 의미를 바로 알 수 있었다. 실제로 현재 다니는 회사에서 새로 시작하게된 프로젝트에서 이전 프로젝트에서 활용하던 Redux를 그대로 채용하자고 했을 때 Zustand를 적극 추천하며 팀원을 설득한 끝에 Zustand를 본격 도입할 수 있었다. 그 이후 모두에게 확실히 편하게 써서 좋다는 말을 듣고 팀 단위에서 DX를 높인 것 같아 괜히 뿌듯했다. ㅎ