상태 관리

Zustand

spacew 2024. 8. 22. 18:38

Zustand는 가볍고 빠르며 확장 가능한 상태 관리 라이브러리로, 다양한 기능과 사용 패턴을 제공합니다.


Zustand: 간단하고 강력한 상태 관리 라이브러리

Zustand는 React 환경에서 간편하게 사용할 수 있는 상태 관리 라이브러리로, Flux 패턴에서 영감을 받아 설계되었습니다. Redux처럼 설정이 복잡하지 않으면서도 성능이 뛰어나며, 필요한 상태를 구독하고 액션을 통해 상태를 변경하는 패턴을 제공합니다.

주요 특징

  1. 간단한 API: Zustand의 create 함수를 통해 상태를 정의하고, 이를 Hook 형태로 컴포넌트에서 쉽게 사용할 수 있습니다.
  2. 불필요한 리렌더링 방지: 상태 변경 시 필요한 부분만 리렌더링되며, 선택자를 통해 특정 상태만 구독할 수 있어 성능 최적화가 용이합니다.
  3. 확장성: 미들웨어를 통해 상태를 확장할 수 있으며, 다양한 사용 사례에 대응할 수 있습니다.
  4. React의 최신 기능과 호환: React 18의 동시성 모드와도 잘 통합되며, 서버 사이드 렌더링(SSR)에도 대응할 수 있습니다.

핵심 개념 및 사용법

1. 스토어 생성과 기본 사용법

Zustand에서의 스토어는 상태를 정의하고 관리하는 중심 역할을 합니다. Zustand의 스토어는 create 함수를 사용해 정의됩니다.

import { create } from 'zustand';

const useStore = create((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
  removeAllBears: () => set({ bears: 0 }),
}));

컴포넌트 내에서 상태를 구독하고 업데이트하는 방식도 매우 간단합니다.

function BearCounter() {
  const bears = useStore((state) => state.bears);
  return <h1>{bears} 마리의 곰이 있습니다.</h1>;
}

function Controls() {
  const increasePopulation = useStore((state) => state.increasePopulation);
  return <button onClick={increasePopulation}>곰 추가</button>;
}

2. 불변 상태 관리와 병합

Zustand는 불변 상태 관리를 지원하며, 상태 병합을 자동으로 처리합니다. 상태를 부분적으로 업데이트하는 경우에도 불변성을 유지하며, 깊은 상태 객체를 쉽게 관리하기 위해 immer와 같은 미들웨어를 사용할 수 있습니다.

3. 자동 선택자 생성(Auto Generating Selectors)

Zustand는 상태 구독 시 특정 속성만 구독할 수 있는 선택자(Selector)를 제공합니다. 선택자를 통해 특정 상태만 구독하면 불필요한 리렌더링을 방지할 수 있습니다. 예를 들어, 상태에서 곰의 수만 구독할 수 있습니다.

const bears = useStore((state) => state.bears);

4. 상태 초기화(Resetting State)

Zustand는 상태를 쉽게 초기화할 수 있습니다. 이를 통해 특정 상태나 전체 상태를 초기값으로 리셋하는 기능을 구현할 수 있습니다.

const useStore = create((set) => ({
  bears: 0,
  resetBears: () => set({ bears: 0 }),
}));

5. 서버 사이드 렌더링(SSR) 및 하이드레이션

Zustand는 서버 사이드 렌더링을 지원하며, 클라이언트에서 하이드레이션이 완료된 후에도 상태가 유지되도록 설정할 수 있습니다. Next.js와 같은 SSR 프레임워크와도 호환됩니다.

// Next.js에서 Zustand를 사용한 예시
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useStore = create(persist((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
}), { name: 'bear-store' }));

6. TypeScript 지원

Zustand는 TypeScript와 완벽하게 호환됩니다. 타입을 사용하여 상태와 액션을 정의하고, 이를 컴포넌트에서 안전하게 사용할 수 있습니다.

import { create } from 'zustand';

interface BearState {
  bears: number;
  increasePopulation: () => void;
}

const useStore = create<BearState>((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
}));

고급 기능

1. Persist 미들웨어

상태를 로컬 스토리지 또는 세션 스토리지에 저장할 수 있는 persist 미들웨어를 제공합니다. 이 기능을 사용하면 페이지 새로고침 후에도 상태가 유지됩니다.

import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useStore = create(persist((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
}), { name: 'bear-storage' }));

2. Immer 미들웨어

immer 미들웨어를 사용하면 상태를 불변성 있게 쉽게 업데이트할 수 있습니다. 이는 복잡한 상태 객체의 깊은 부분을 변경하는 데 유용합니다.

import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';

const useStore = create(immer((set) => ({
  user: { name: '', age: 0 },
  updateName: (name) => set((state) => { state.user.name = name; }),
})));

3. Redux DevTools 지원

Zustand는 Redux DevTools와 통합할 수 있어, 상태의 변화를 시각적으로 추적하고 디버깅할 수 있습니다.

import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

const useStore = create(devtools((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
})));

결론

Zustand는 리액트 기반 프로젝트에서 간편하고 확장성 있는 상태 관리 솔루션을 제공합니다. Redux보다 간결한 API와 뛰어난 성능 최적화 기능을 갖추고 있으며, 다양한 미들웨어와의 통합으로 유연한 상태 관리가 가능합니다.