리액트에서 프로젝트가 커질수록 컴포넌트 간 상태 공유가 점점 복잡해집니다.
단순히 useState나 props drilling만으로는 관리가 힘들어지고, 이 때문에 다양한 상태 관리 라이브러리가 등장했습니다. 대
표적으로 Redux, MobX, Recoil 등이 있습니다..
그중에서 최근 많이 주목받는 Zustand는 단순함과 가벼움으로 개발자들에게 인기를 얻고 있습니다.
왜 Zustand인가?
- 간단한 문법
- Redux처럼 action, reducer, dispatch를 정의하지 않아도 됩니다.
- create() 함수 하나로 전역 상태를 만들 수 있습니다.
- 가벼운 크기
- 패키지 크기가 작아 빌드에 부담이 적습니다.
- Hooks 기반 사용
- 마치 useState처럼 간단히 불러와 사용합니다.
- 유연성
- Flux 구조를 강제하지 않아, 원하는 방식으로 상태를 설계할 수 있습니다.
- SSR 지원
- Next.js 환경에서도 hydration 문제를 쉽게 해결할 수 있습니다.
즉, “필요한 만큼만 쓰고 싶다”는 요구를 충족하는 라이브러리입니다.
설치하기
Next.js 프로젝트에 Zustand를 설치하려면 아래 명령어를 실행합니다.
npm install zustand
또는 yarn을 사용하는 경우
yarn add zustand
예제 – 카운터 만들기
Zustand의 기본 개념을 이해하기 위해 가장 단순한 카운터 예제를 만들어보겠습니다.
Store 정의하기
먼저 store/useCounter.ts 파일을 만들어 상태를 정의합니다.
// store/useCounter.ts
import { create } from "zustand";
interface CounterState {
count: number;
increase: () => void;
decrease: () => void;
reset: () => void;
}
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
decrease: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
- 여기서 set 함수는 Zustand가 제공하는 상태 업데이트 함수입니다.
- React의 setState와 비슷하지만, 전역적으로 관리된다는 점이 다릅니다.
컴포넌트에서 사용하기
Next.js App Router 환경에서 page.tsx 파일에서 이 상태를 불러와 사용합니다.
// app/page.tsx
"use client";
import { useCounterStore } from "@/store/useCounter";
export default function HomePage() {
const { count, increase, decrease, reset } = useCounterStore();
return (
<div className="flex flex-col items-center gap-4 py-10">
<h1 className="text-2xl font-bold">Zustand Counter Example</h1>
<p className="text-lg">Current Count: {count}</p>
<div className="flex gap-2">
<button
onClick={increase}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
+1
</button>
<button
onClick={decrease}
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
>
-1
</button>
<button
onClick={reset}
className="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600"
>
Reset
</button>
</div>
</div>
);
}
- +1 버튼을 누르면 count가 1씩 증가합니다.
- -1 버튼을 누르면 count가 1씩 감소합니다.
- Reset 버튼을 누르면 count가 0으로 초기화됩니다.
이 모든 것이 전역 상태로 관리되기 때문에, 다른 컴포넌트에서도 동일한 값을 손쉽게 참조할 수 있습니다.
동작 방식
Zustand를 쓰면 마치 useState처럼 간단하게 상태를 가져오지만, 차이점은 다음과 같습니다
- 상태는 전역적으로 공유됩니다. 즉, 어떤 컴포넌트에서든 동일한 값을 접근 가능
- 여러 컴포넌트에서 동시에 값이 업데이트되어도 자동으로 최신 값이 반영됨
- 코드 양이 적고, Redux처럼 복잡한 보일러플레이트가 없음
예를 들어, 다른 컴포넌트에서 useCounterStore를 불러와도 같은 count 값이 공유됩니다.
이는 props drilling 없이 상태를 주고받을 수 있음을 의미합니다.
Next.js 유의할 점
- App Router에서 use client 선언 필수
- Zustand store를 불러오는 컴포넌트는 클라이언트 컴포넌트이므로 반드시 상단에 "use client"를 선언해야 합니다.
- SSR과 Hydration 문제
- Zustand는 클라이언트 사이드 전역 상태 관리에 강점이 있으므로, 서버에서 상태를 초기화하거나 persist 기능을 쓰는 경우 주의해야 합니다. (이 부분은 2차 블로그 글에서 다룰 예정)
- 코드 분리
- store 파일은 store/ 디렉토리에 모아두면 관리하기 편리합니다.
Zustand 장점
- 코드가 간결하고 러닝커브가 낮음
- 여러 컴포넌트에서 전역 상태를 props 없이 쉽게 공유 가능
- Next.js 환경에서도 잘 동작하며, SSR과도 궁합이 맞음
- Redux와 달리 boilerplate가 거의 없어 빠르게 적용 가능
'개발 공부 > React' 카테고리의 다른 글
| Server Components, Client Components (0) | 2025.09.03 |
|---|---|
| useOptimistic (0) | 2025.08.28 |
| React Recoil (3) | 2025.08.16 |
| React Query, Redux Toolkit Query (0) | 2025.06.22 |
| TanStack Query (0) | 2025.05.22 |