Files
2nd/10_Wiki/Topics/AI_and_ML/상태 관리 최적화 (Zustand Jotai Valtio).md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

6.5 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-상태-관리-최적화-zustand-jotai-valtio 상태 관리 최적화 (Zustand Jotai Valtio) 10_Wiki/Topics verified self
Modern React State
Zustand Jotai Valtio
Atomic State Management
none A 0.9 applied
react
state-management
zustand
jotai
valtio
performance
2026-05-10 pending
language framework
typescript React-19

상태 관리 최적화 (Zustand · Jotai · Valtio)

매 한 줄

"매 right tool 의 매 right granularity". 매 React 19 (2026) 시대, Redux 의 boilerplate 없이 매 selective subscription 으로 re-render 최소화 — Zustand (store-based, 매 simple), Jotai (atomic, 매 fine-grained), Valtio (proxy-based, 매 mutable feel) 의 매 성격 다른 trio.

매 핵심

매 세 라이브러리 비교

  • Zustand: 단일 store + selector subscription. 매 Redux replacement 의 80% 케이스. ~3kb.
  • Jotai: atom 단위 state, atom 의 dependency graph. 매 fine-grained re-render. ~5kb.
  • Valtio: proxy 로 mutable mutation, 매 reactive subscribe. ~3kb. 매 immer 대체.
  • 매 셋 모두 React 19 의 useSyncExternalStore 와 매 native concurrent rendering 지원.

매 선택 축

  • Granularity: Jotai (atom) > Valtio (proxy path) > Zustand (selector).
  • Mental model: Zustand (store) > Valtio (mutable) > Jotai (atom graph).
  • DevTools: Zustand (Redux DevTools) > Jotai (Jotai DevTools) > Valtio (proxy log).

매 응용

  1. App-wide state (auth, theme): Zustand single store.
  2. Cross-component derived state: Jotai atoms with atom((get) => ...).
  3. Form / canvas / heavy mutation: Valtio (mutable feel).

💻 패턴

Zustand store + selector

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

interface AuthStore {
  user: User | null;
  login: (u: User) => void;
  logout: () => void;
}

export const useAuth = create<AuthStore>()(
  devtools(
    persist(
      (set) => ({
        user: null,
        login: (user) => set({ user }, false, 'auth/login'),
        logout: () => set({ user: null }, false, 'auth/logout'),
      }),
      { name: 'auth' },
    ),
  ),
);

// Component — selective subscribe
const userName = useAuth((s) => s.user?.name);

Zustand slice pattern (large store)

const createAuthSlice: StateCreator<AuthSlice> = (set) => ({ /* ... */ });
const createCartSlice: StateCreator<CartSlice> = (set) => ({ /* ... */ });

export const useStore = create<AuthSlice & CartSlice>()((...a) => ({
  ...createAuthSlice(...a),
  ...createCartSlice(...a),
}));

Jotai atomic state

import { atom, useAtom, useAtomValue } from 'jotai';

const countAtom = atom(0);
const doubledAtom = atom((get) => get(countAtom) * 2);

const asyncUserAtom = atom(async (get) => {
  const id = get(userIdAtom);
  return fetch(`/api/u/${id}`).then(r => r.json());
});

function Counter() {
  const [count, setCount] = useAtom(countAtom);
  const doubled = useAtomValue(doubledAtom); // re-renders only when doubled changes
  return <button onClick={() => setCount(c => c + 1)}>{doubled}</button>;
}

Jotai atomFamily (dynamic per-id atoms)

import { atomFamily } from 'jotai/utils';

const todoAtomFamily = atomFamily((id: string) =>
  atom({ id, text: '', done: false }),
);

function Todo({ id }: { id: string }) {
  const [todo, setTodo] = useAtom(todoAtomFamily(id));
  // only this Todo re-renders when its atom changes
}

Valtio proxy mutable state

import { proxy, useSnapshot, subscribe } from 'valtio';

const canvasState = proxy({
  shapes: [] as Shape[],
  selected: null as string | null,
  zoom: 1,
});

// Mutation (no setState!)
function addShape(s: Shape) {
  canvasState.shapes.push(s);
}

function ShapeList() {
  const snap = useSnapshot(canvasState); // immutable snapshot, fine-grained
  return <>{snap.shapes.map(s => <ShapeView key={s.id} {...s} />)}</>;
}

Re-render audit (React DevTools profiler)

// Zustand: shallow equal for object selectors
import { shallow } from 'zustand/shallow';
const { x, y } = useStore((s) => ({ x: s.x, y: s.y }), shallow);

// Jotai: selectAtom for partial reads
import { selectAtom } from 'jotai/utils';
const userNameAtom = selectAtom(userAtom, (u) => u.name);

SSR / RSC integration (Next.js 15+)

// Zustand — per-request store (avoid module singleton on server)
export const StoreProvider = ({ children, initialState }) => {
  const storeRef = useRef<Store>();
  if (!storeRef.current) storeRef.current = createStore(initialState);
  return <Context.Provider value={storeRef.current}>{children}</Context.Provider>;
};

매 결정 기준

상황 Approach
Simple global state (auth, UI) Zustand
Complex derived/async chains Jotai
Heavy mutation (canvas, editor, form) Valtio
Server state (queries, mutations) TanStack Query (not these)
Tree-wide config that rarely changes React Context
Time-travel + middleware ecosystem Redux Toolkit (still valid)

기본값: 매 신규 React 19 앱 → Zustand. 매 fine-grained 필요 → Jotai 추가. 매 server state → TanStack Query separate.

🔗 Graph

🤖 LLM 활용

언제: store shape 의 first scaffold, selector boilerplate 생성, 매 atom dependency graph 시각화. 언제 X: 매 actual perf 측정 — profiler 만 truth. Library choice 의 매 nuanced trade-off 도 매 LLM 의 over-confident 영역.

안티패턴

  • Single mega-store (Zustand): selector 로 mitigate 가능하지만, atom split 가 더 clean.
  • Atom explosion (Jotai): 매 trivial state 의 atom 화 → 매 cognitive overhead.
  • Direct Valtio mutation in render: 매 React rule violation. mutation 은 event handler 또는 effect 내.
  • Context for high-frequency state: 매 entire subtree re-render. 매 use these libs instead.
  • Mixing server + client state: 매 TanStack Query 의 영역, store 에 넣지 마.

🧪 검증 / 중복

  • Verified (Zustand v5 docs 2026, Jotai v2 docs, Valtio v2 docs, Daishi Kato writings).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — Zustand/Jotai/Valtio 비교 + React 19 패턴