Skip to content

Zustand

Reference

📎 Zustand Docs

상태관리의 필요성

리액트 애플리케이션은 규모가 커질수록 상태(state) 관리가 복잡해진다.
대표적인 문제점들은 다음과 같다:

  • Props Drilling: 하위 컴포넌트까지 불필요하게 props를 전달해야 함
  • 복잡한 상태 흐름: 여러 곳에서 상태를 읽고 수정하면서 추적이 어려워 짐
  • 컴포넌트 간 의존성 증가: 컴포넌트가 상태에 강하게 묶여 결합도가 커짐
  • Context API의 한계: 전역 공유는 가능하지만, 성능 이슈와 리렌더링 문제가 발생하기 쉬움

예시: 댓글 생성 시 필요한 상태 흐름

  • 입력값 초기화
  • 로딩 상태 처리
  • 새 댓글 목록 반영

상태가 여러 컴포넌트에 흩어져 있다 보면, 어디서 어떤 상태가 바뀌는지 추적하기 어렵다.

Zustand 소개

Zustand란?

  • 독일어로 상태라는 의미
  • 2019년, Poimandres 팀에서 개발
  • React의 Hooks와 자연스럽게 통합되는 경량 상태 관리 라이브러리

기본 사용 예시

jsx
import { create } from "zustand";

const useStore = create((set) => ({
  count: 0,
  increment: () => set((s) => ({ count: s.count + 1 })),
}));

function Counter() {
  const { count, increment } = useStore();
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increment}>+1</button>
    </div>
  );
}
  • create 함수로 상태와 업데이트 함수를 정의
  • 컴포넌트에서는 useStore 훅을 호출해 바로 사용 가능
  • 상태와 로직이 한 곳에 모여 관리가 단순해진다.

Zustand 장점

  • 간결함: 보일러플레이트 코드가 거의 없음
  • 낮은 러닝커브: 훅 기반 API라 쉽게 학습 가능
  • 유연한 구조: 작은 프로젝트부터 큰 프로젝트까지 적용 가능
  • Provider 불필요: Context Provider 없이 전역 상태 사용 가능
jsx
function DeepComponent() {
  const count = useStore((state) => state.count);
  return <div>{count}</div>;
}
  • 리렌더링 최적화: 필요한 상태만 선택적으로 구독 가능
jsx
const count = useStore((state) => state.count);
const increment = useStore((state) => state.increment);
// count가 변해도 increment는 다시 렌더링되지 않음
  • TypeScript 지원 - 필요한 상태만 선택적으로 구독 가능

다른 라이브러리와의 비교

라이브러리특징복잡도러닝커브
Redux보일러플레이트 많음높음높음
Context API내장 기능, 성능 이슈 있음중간중간
Jotai / Recoil원자 기반 상태, 의존성 표현중간중간
Zustand간결하고 직관적, 성능 최적화낮음낮음

왜 Zustand를 배워야 할까?

  • 복잡한 상태 관리 문제를 간결하고 직관적으로 해결
  • React 프로젝트에 바로 적용 가능
  • 러닝 커브가 낮아 학습 효율이 높음

Redux vs Zustand

  • Redux: 액션, 리듀서, 미들웨어 등 구조가 무겁고 복잡
  • Zustand: 단일 스토어, 훅 기반, 직관적인 API → 한 줄로 상태와 업데이트 로직을 정의할 수 있음
    jsx
    // Zustand는 한 줄로 상태 + 함수 구성
    create (() => ({ count: 0, inc: () => {...} }))