728x90
728x90

Zustand

들어가며

  • 전역 상태 라이브러리 중 하나인 Zustand에 대해 간단하게 정리해본다.

 

Zustand

개념

  • 독일어로 상태(Status)라는 뜻
  • 리액트 앱에서 전역 상태 관리를 해주는 아주 가볍고 단순한 라이브러리
  • Redux의 복잡한 구조(Action, Reducer, Dispatch)를 사용하지 않고, Hooks 기반의 간단한 API 제공
  • "minimal, fast, scalable"을 목표로 만들어졌다.

 

비교

Redux와 비교

  • Redux는 boilerplate한 코드가 많다.
    • @action@, @reducer@, @slice@를 작성해야 한다.
// Redux Toolkit
const slice = createSlice({
  name: "counter",
  initialState: { count: 0 },
  reducers: { increment: (state) => { state.count++ } }
});

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

 

Context API와 비교

  • Context API는 Provider/Consumer 패턴이 필요하며 리렌더링 문제 발생한다.
  • Zustand는 구독 단위(state selector)를 지원하여 리렌더링을 최적화할 수 있다.
// Context API - 전부 리렌더링됨
const { user } = useContext(UserContext);

// Zustand - 필요한 데이터만 구독
const username = useUserStore((state) => state.user.name);

 

사용 방법

기본 사용 방법

import { create } from "zustand";

// 1. 상태 정의
const useCounterStore = create((set) => ({
  count: 0,
  increment: () => set((s) => ({ count: s.count + 1 })),
  decrement: () => set((s) => ({ count: s.count - 1 })),
}));

// 2. 컴포넌트에서 사용
function Counter() {
  const { count, increment, decrement } = useCounterStore();
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>-1</button>
    </div>
  );
}

 

선택적 구독 (Selector 사용)

function CountValue() {
  const count = useCounterStore((state) => state.count);
  return <h1>{count}</h1>;
}

function CountButtons() {
  const increment = useCounterStore((state) => state.increment);
  return <button onClick={increment}>+1</button>;
}

 

미들웨어 활용

  • @persist@ : 상태를 localStorage 등에 자동 저장
  • @devtools@ : Redux DevTools와 연동
import { create } from "zustand";
import { persist, devtools } from "zustand/middleware";

const useUserStore = create(
  devtools(
    persist(
      (set) => ({
        name: "guest",
        setName: (name) => set({ name }),
      }),
      { name: "user-storage" } // localStorage key
    )
  )
);

 

전역 스토어 분리

  • 여러 개의 store를 만들어 관리 가능
  • 관심사 분리 (예: @useUserStore@, @useCartStore@)
export const useUserStore = create((set) => ({
  name: "",
  setName: (name) => set({ name }),
}));

export const useCartStore = create((set) => ({
  items: [],
  addItem: (item) => set((s) => ({ items: [...s.items, item] })),
}));

 

비동기 로직

  • @async@/@await@ 사용 가능
  • API 호출 후 상태 업데이트
const useTodoStore = create((set) => ({
  todos: [],
  fetchTodos: async () => {
    const res = await fetch("/api/todos");
    const data = await res.json();
    set({ todos: data });
  },
}));

 

공식 문서

 

Introduction - Zustand

How to use Zustand

zustand.docs.pmnd.rs

 

참고 사이트

 

Introduction - Zustand

How to use Zustand

zustand.docs.pmnd.rs

 

728x90
728x90