[React] Zustand로 배우는 간단하고 강력한 상태 관리

2024. 12. 20. 10:59·TypeScript
반응형

소개

Zustand는 React를 위한 작고 빠른 상태 관리 라이브러리입니다. Redux의 복잡성을 줄이면서도 강력한 기능을 제공하는 Zustand의 사용법을 알아보겠습니다.

설치

# npm
npm install zustand

# yarn
yarn add zustand

# pnpm
pnpm add zustand

기본적인 스토어 생성과 사용

스토어 생성

// stores/useCounterStore.ts
import { create } from 'zustand';

interface CounterState {
  count: number;
  increment: () => void;
  decrement: () => void;
  reset: () => void;
}

const useCounterStore = create<CounterState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
  reset: () => set({ count: 0 })
}));

export default useCounterStore;

컴포넌트에서 사용

// components/Counter.tsx
import useCounterStore from '../stores/useCounterStore';

function Counter() {
  const { count, increment, decrement, reset } = useCounterStore();

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

비동기 액션 처리

// stores/useUserStore.ts
interface UserState {
  user: User | null;
  loading: boolean;
  error: string | null;
  fetchUser: (id: string) => Promise<void>;
}

const useUserStore = create<UserState>((set) => ({
  user: null,
  loading: false,
  error: null,
  fetchUser: async (id) => {
    try {
      set({ loading: true, error: null });
      const response = await fetch(`/api/users/${id}`);
      const user = await response.json();
      set({ user, loading: false });
    } catch (error) {
      set({ error: error.message, loading: false });
    }
  }
}));

상태 구독과 선택적 업데이트

// 특정 상태만 구독
function UserName() {
  const userName = useUserStore((state) => state.user?.name);
  return <div>{userName}</div>;
}

// 여러 상태 구독
function UserStatus() {
  const { loading, error } = useUserStore((state) => ({
    loading: state.loading,
    error: state.error
  }));

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  return null;
}

미들웨어 활용

로깅 미들웨어

const logMiddleware = (config) => (set, get, api) =>
  config(
    (...args) => {
      console.log('이전 상태:', get());
      set(...args);
      console.log('다음 상태:', get());
    },
    get,
    api
  );

const useStore = create(
  logMiddleware((set) => ({
    // store 구현
  }))
);

영속성 미들웨어

import { persist } from 'zustand/middleware';

const useStore = create(
  persist(
    (set) => ({
      // store 구현
    }),
    {
      name: 'storage-key',
      getStorage: () => localStorage
    }
  )
);

타입스크립트와의 통합

interface TodoState {
  todos: Todo[];
  addTodo: (text: string) => void;
  removeTodo: (id: string) => void;
  toggleTodo: (id: string) => void;
}

interface Todo {
  id: string;
  text: string;
  completed: boolean;
}

const useTodoStore = create<TodoState>((set) => ({
  todos: [],
  addTodo: (text) => 
    set((state) => ({
      todos: [...state.todos, { 
        id: Date.now().toString(), 
        text, 
        completed: false 
      }]
    })),
  removeTodo: (id) =>
    set((state) => ({
      todos: state.todos.filter(todo => todo.id !== id)
    })),
  toggleTodo: (id) =>
    set((state) => ({
      todos: state.todos.map(todo =>
        todo.id === id 
          ? { ...todo, completed: !todo.completed }
          : todo
      )
    }))
}));

성능 최적화

메모이제이션 활용

function TodoList() {
  const todos = useTodoStore((state) => state.todos);
  const addTodo = useTodoStore((state) => state.addTodo);

  // 메모이제이션된 필터링
  const completedTodos = useMemo(
    () => todos.filter(todo => todo.completed),
    [todos]
  );

  return (
    <div>
      {completedTodos.map(todo => (
        <TodoItem key={todo.id} todo={todo} />
      ))}
    </div>
  );
}

선택적 렌더링

const TodoCount = memo(() => {
  const count = useTodoStore((state) => state.todos.length);
  return <div>Total todos: {count}</div>;
});

실전 활용 예제

인증 상태 관리

interface AuthState {
  user: User | null;
  token: string | null;
  login: (credentials: Credentials) => Promise<void>;
  logout: () => void;
  updateUser: (userData: Partial<User>) => void;
}

const useAuthStore = create<AuthState>()(
  persist(
    (set) => ({
      user: null,
      token: null,
      login: async (credentials) => {
        const response = await loginApi(credentials);
        set({ user: response.user, token: response.token });
      },
      logout: () => set({ user: null, token: null }),
      updateUser: (userData) =>
        set((state) => ({
          user: state.user ? { ...state.user, ...userData } : null
        }))
    }),
    {
      name: 'auth-storage'
    }
  )
);

마치며

Zustand는 단순하면서도 강력한 상태 관리 솔루션을 제공합니다. Redux의 보일러플레이트 없이도 복잡한 상태 관리를 할 수 있으며, TypeScript와의 통합도 매우 자연스럽습니다.

사용 시 주의사항

  1. 상태 업데이트는 항상 불변성을 지켜야 합니다.
  2. 큰 상태 객체는 적절히 분리하여 관리하세요.
  3. 성능 최적화를 위해 선택적 구독을 활용하세요.
저작자표시 비영리 변경금지 (새창열림)

'TypeScript' 카테고리의 다른 글

[React] memo를 사용한 컴포넌트 최적화  (0) 2024.12.25
[React Query] useMutation과 useQuery  (0) 2024.12.24
[React Query] QueryClient : 효율적인 상태관리와 데이터 캐싱  (0) 2024.12.19
프론트엔드와 백엔드 간 Enum 동기화  (0) 2024.12.07
React 환경 변수 : .env  (1) 2024.12.05
'TypeScript' 카테고리의 다른 글
  • [React] memo를 사용한 컴포넌트 최적화
  • [React Query] useMutation과 useQuery
  • [React Query] QueryClient : 효율적인 상태관리와 데이터 캐싱
  • 프론트엔드와 백엔드 간 Enum 동기화
코샵
코샵
나의 코딩 일기장
    반응형
  • 코샵
    끄적끄적 코딩 공방
    코샵
    • 분류 전체보기 (727)
      • 스마트팜 (1)
      • 상품 추천 (223)
      • DataBase (0)
        • MongoDB (4)
        • PostgreSQL (0)
      • 하드웨어 (18)
      • 일기장 (4)
      • 파이썬 (130)
        • Basic (41)
        • OpenCV (8)
        • Pandas (15)
        • PyQT (3)
        • SBC(Single Board Computer) (1)
        • 크롤링 (14)
        • Fast API (29)
        • Package (6)
      • Unity (138)
        • Tip (41)
        • Project (1)
        • Design Pattern (8)
        • Firebase (6)
        • Asset (2)
      • Linux (4)
      • C# (97)
        • Algorithm (11)
        • Window (7)
      • TypeScript (51)
        • CSS (10)
      • Git (11)
      • SQL (5)
      • Flutter (10)
        • Tip (1)
      • System (1)
      • BaekJoon (6)
      • Portfolio (2)
      • MacOS (1)
      • 유틸리티 (1)
      • 서비스 (6)
      • 자동화 (3)
      • Hobby (10)
        • 물생활 (10)
        • 식집사 (0)
  • 인기 글

  • 태그

    cv2
    C#
    스크립트 실행 순서
    파이썬
    라떼우유
    유니티
    스마트스토어리뷰
    codingcommunity
    Python
    카페24리뷰이관
    리뷰이관
    셀레니움
    unity
    appdevelopment
    상품 리뷰 크롤링
    스크립트 실행
    믈레코비타멸균우유
    rtsp
    list
    쇼핑몰리뷰
    programming101
    codingtips
    리스트
    devlife
    긴유통기한우유
    카페24리뷰
    ipcamera
    programmerlife
    리뷰관리
    learntocode
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
코샵
[React] Zustand로 배우는 간단하고 강력한 상태 관리
상단으로

티스토리툴바