# React State Management

> Select and implement local, global, and server state patterns in React. Use when choosing or implementing state management (Context, Zustand, Redux, React Query) in React.

- Skill: `hoangnguyen0403/react-state-management` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add hoangnguyen0403/react-state-management`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hoangnguyen0403/react-state-management/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: HoangNguyen0403 (https://skillmd.com/u/hoangnguyen0403)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/hoangnguyen0403/react-state-management

---

# React State Management

## **Priority: P0 (CRITICAL)**


## Implementation Guidelines

- **Selection**: **Zustand for small-medium apps** (minimal boilerplate, no Providers). **Redux Toolkit (RTK) for large apps** needing **time-travel debugging** or complex middleware.
- **Server Data**: **Use React Query or SWR for server state**. **Never sync server data into `useState`** manually. Let **cache source of truth**.
- **Form/Mutation State (React 19)**: Use `useActionState` for a form's pending/result/error triad instead of three separate `useState` calls; use `useOptimistic` to show an optimistic value while a mutation is in flight, reverting on error automatically.
- **Context API**: Use for **low-frequency data** like **theme, auth, locale**, or DI. Not for high-frequency updates (causes global re-renders). **Split Context** between State and Dispatch to optimize.
- **Global Updates**: Use **Zustand, Jotai, or Redux for frequent/complex updates** across app.
- **Local**: `useState` for simple UI toggles. `useReducer` for complex state machines.
- **Derived**: Compute at render time (`const fullName = ...`). No `useEffect` to sync state.
- **URL**: Store filter/sort params in **URL Search Params** (Single Source of Truth).
- **Immutability**: Never mutate. Use spread or Immer. Use `useMemo` on context value to prevent unnecessary re-renders (primitive performance tuning belongs in `hooks` skill).

> **Boundary note**: `hooks` skill covers primitive API usage (`useMemo`, `useCallback` rules). This skill covers _architectural_ state decisions — which tool to use for which state scope.

```tsx
function LikeButton({ postId, initialLiked }: { postId: string; initialLiked: boolean }) {
  const [optimisticLiked, setOptimisticLiked] = useOptimistic(initialLiked);
  return (
    <button
      onClick={async () => {
        setOptimisticLiked(!optimisticLiked);
        await toggleLike(postId);
      }}
    >
      {optimisticLiked ? 'Liked' : 'Like'}
    </button>
  );
}
```

## Verify

- [ ] Form pending/error/result state uses `useActionState`, not three `useState` calls.
- [ ] In-flight mutation UI uses `useOptimistic` rather than a manual "isSaving" flag.
- [ ] Server data lives in React Query/SWR cache, never duplicated into `useState`.

## Reference & Examples

For Zustand, Redux Toolkit, and TanStack Query patterns:
See [references/REFERENCE.md](references/REFERENCE.md).

## Anti-Patterns

- **No Context for High-Freq**: Use Zustand/Redux for state that changes frequently.
- **No State Sync**: Compute derived values during render; avoid `useEffect` to sync state.
- **No Server Cache as UI State**: React Query/SWR for server data; don't duplicate into `useState`.
- **No Manual Optimistic Flags**: Use `useOptimistic` instead of a hand-rolled temporary state + rollback.
