C
React/상태심화/Lesson 17

Zustand 전역 상태 관리

30분·theory
TypeScript

Zustand 전역 상태 관리

💡 왜 배워야 할까요?

🎯 Redux보다 번들 크기가 95% 작으면서 같은 기능을 합니다.
💼 보일러플레이트 코드 없이 직관적으로 전역 상태를 관리합니다.
TypeScript 지원이 완벽해 타입 안정성이 뛰어납니다.
🔗 2024년 현재 스타트업과 대기업 모두 Zustand로 전환 중입니다.
🏢 실무에서는
실무에서는 사용자 로그인 정보, 테마 설정, 장바구니 등을 Zustand로 관리합니다. Redux처럼 복잡한 액션/리듀서 작성 없이 간단한 함수로 상태를 변경하고, 어떤 컴포넌트에서든 필요한 상태만 구독해서 사용합니다.

개념

2025년 현재 React 상태관리의 양대 산맥인 Zustand와 Recoil의 실무 선택 기준을 학습합니다. 번들 크기, 러닝커브, 타입 안정성 등 실제 프로젝트에서 고려해야 할 모든 요소를 다룹니다.

왜 중요한가?

대규모 서비스에서 Redux 대신 Zustand를 도입해 번들 크기를 30% 줄이고 개발 생산성을 2배 향상시킨 사례가 늘고 있습니다. 특히 Meta에서 개발한 Recoil과 함께 차세대 상태관리 솔루션으로 주목받고 있어, 2025년 프론트엔드 면접에서 필수 질문으로 등장하고 있습니다.

핵심 개념

Zustand는 '독일어로 상태'라는 뜻으로, 매우 가벼운 상태관리 라이브러리입니다. 마치 작은 서랍장처럼 필요한 상태만 간단히 보관합니다. Recoil은 페이스북이 만든 atomic 기반 상태관리로, 레고 블록처럼 작은 상태 단위들을 조합해서 복잡한 상태를 만듭니다.

핵심 포인트

  • Zustand: 2.9KB vs Recoil: 79KB - 번들 크기에서 Zustand 압승
  • Zustand는 보일러플레이트 없음, Recoil은 atom/selector 패턴으로 세밀한 제어
  • 2025년 기준 Zustand가 더 안정적, Recoil은 여전히 실험적 단계
💻 Zustand 기본 구현 - 2025 권장 패턴
import { create } from 'zustand'
import { persist } from 'zustand/middleware'

// 2025년 최신 패턴: immer와 persist 조합
interface UserStore {
  user: User | null
  isLoading: boolean
  login: (credentials: LoginCredentials) => Promise<void>
  logout: () => void
}

export const useUserStore = create<UserStore>()(persist(
  (set, get) => ({
    user: null,
    isLoading: false,
    
    login: async (credentials) => {
      set({ isLoading: true })
      try {
        const user = await authAPI.login(credentials)
        set({ user, isLoading: false })
      } catch (error) {
        set({ isLoading: false })
        throw error
      }
    },
    
    logout: () => {
      set({ user: null })
      authAPI.logout()
    }
  }),
  {
    name: 'user-storage',
    partialize: (state) => ({ user: state.user }) // 필요한 것만 persist
  }
))
💻 Recoil 기본 구현 - Atomic 패턴
import { atom, selector, useRecoilState, useRecoilValue } from 'recoil'

// Atom 정의
export const userAtom = atom<User | null>({
  key: 'userAtom',
  default: null,
})

export const isLoadingAtom = atom<boolean>({
  key: 'isLoadingAtom',
  default: false,
})

// Selector로 파생 상태 정의
export const userStatusSelector = selector({
  key: 'userStatusSelector',
  get: ({ get }) => {
    const user = get(userAtom)
    const isLoading = get(isLoadingAtom)
    
    if (isLoading) return 'loading'
    if (user) return 'authenticated'
    return 'guest'
  },
})

// 컴포넌트에서 사용
function UserProfile() {
  const [user, setUser] = useRecoilState(userAtom)
  const userStatus = useRecoilValue(userStatusSelector)
  
  return (
    <div>
      <p>상태: {userStatus}</p>
      {user && <p>환영합니다, {user.name}님!</p>}
    </div>
  )
}

💡 ⚠️ 흔한 실수

  • Zustand에서 불필요하게 여러 스토어를 분리해서 props drilling 문제를 다시 만들어내는 경우
  • Recoil에서 atom key를 중복으로 사용해서 예상치 못한 상태 공유가 발생하는 경우
  • 번들 크기를 고려하지 않고 소규모 프로젝트에 Recoil을 도입해서 오버엔지니어링하는 경우

💡 🎯 면접 준비

Q: Zustand와 Recoil 중 어느 것을 선택하겠습니까? 그 이유는?
Q: Redux 대비 Zustand의 장점은 무엇인가요?
Q: Recoil의 atom과 selector 패턴을 설명해보세요

힌트: 프로젝트 규모와 팀 상황을 기준으로 선택 - 소중규모/빠른 개발은 Zustand, 대규모/복잡한 상태 의존성은 Recoil. 번들 크기, 학습 곡선, 타입 안정성, 커뮤니티 지원을 종합적으로 언급하며 실무 경험 사례 포함

⚛️ React 패턴 — Zustand 전역 상태 관리

Zustand 전역 상태 관리을 React에서 어떻게 쓰는지 코드와 함께 단계별로 익혀보세요.
1 🧩 1. Zustand 전역 상태 관리 사용 시나리오
이 기능이 필요한 상황.
2 💻 2. 코드 작성
Zustand 전역 상태 관리의 기본 사용법.
3 🎨 3. 렌더링 결과
사용자가 보는 화면.
4 💡 4. 실무 팁
흔한 함정과 베스트 프랙티스.

🎮 Zustand 전역 상태 관리 — 단계별 이해

각 단계를 클릭해 내용을 읽고 ✓ 이해했어요 버튼으로 진행률을 확인하세요.
🖥️ 실행 결과 — 렌더링된 React 컴포넌트
✏️ React 코드 수정하기 (클릭해서 열기)
⚛️ React 18 + Babel Standalone — 결과 먼저 확인 후 코드 편집기에서 직접 수정해볼 수 있습니다.

확인 퀴즈

Zustand의 장점으로 올바른 것은?
💡 Zustand는 store 생성, 구독, 업데이트를 최소한의 코드로 작성할 수 있어요. Redux의 복잡한 액션/리듀서/미들웨어 없이 const useStore = create(set => ...)로 시작해요.
먼저 읽으면 좋은 개념: React Query (TanStack Query)
Zustand — 요즘 1티어 전역 상태 - React