본문 바로가기

개발 공부/React

Zustand (1)

리액트에서 프로젝트가 커질수록 컴포넌트 간 상태 공유가 점점 복잡해집니다.

단순히 useStateprops drilling만으로는 관리가 힘들어지고, 이 때문에 다양한 상태 관리 라이브러리가 등장했습니다. 대

표적으로 Redux, MobX, Recoil 등이 있습니다..

그중에서 최근 많이 주목받는 Zustand는 단순함과 가벼움으로 개발자들에게 인기를 얻고 있습니다.

 

 

왜 Zustand인가?

  1. 간단한 문법 
    • Redux처럼 action, reducer, dispatch를 정의하지 않아도 됩니다.
    • create() 함수 하나로 전역 상태를 만들 수 있습니다.
  2. 가벼운 크기
    • 패키지 크기가 작아 빌드에 부담이 적습니다.
  3. Hooks 기반 사용
    • 마치 useState처럼 간단히 불러와 사용합니다.
  4. 유연성
    • Flux 구조를 강제하지 않아, 원하는 방식으로 상태를 설계할 수 있습니다.
  5. 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  유의할 점

  1. App Router에서 use client 선언 필수
    • Zustand store를 불러오는 컴포넌트는 클라이언트 컴포넌트이므로 반드시 상단에 "use client"를 선언해야 합니다.
  2. SSR과 Hydration 문제
    • Zustand는 클라이언트 사이드 전역 상태 관리에 강점이 있으므로, 서버에서 상태를 초기화하거나 persist 기능을 쓰는 경우 주의해야 합니다. (이 부분은 2차 블로그 글에서 다룰 예정)
  3. 코드 분리
    • 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