---
name: react-state-management
description: 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.
metadata:
  triggers:
    files:
      - "**/*.tsx"
      - "**/*.jsx"
    keywords:
      - React state management
      - state in React
      - useReducer
      - React context
      - context in React
      - store
      - props
---

# 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.
