state-disciplinelisted
Install: claude install-skill lukedj78/dev-flow
# state-discipline — `useState` is the last resort
This skill governs **where state lives** in a Next.js 16 App Router / React 19 codebase. The framework's primitives (Server Components, URL `searchParams`, props, query libraries, controlled inputs, `useOptimistic`, `useTransition`) cover ~90% of "I need some state" cases. `useState` and `useEffect` are escape hatches for the last 10%.
The bug is silent: code that uses `useState` + `useEffect` to mirror a prop, derive a value, or sync with the URL **works** — until the source of truth changes and the mirror desyncs. No error, no warning, just wrong UI.
## When this skill applies
- The user pastes `useState + useEffect` and asks for review.
- The user is about to add `useEffect` (at all).
- The user is about to add `useState` to mirror a prop.
- The user asks "should I add `useState` here?".
- The user is about to add `useState` to hold form field values (route them to the `forms` skill).
- The user is about to add `useState` to hold server-fetched data (route them to the `data-fetching` skill).
- The user asks to **audit** a codebase against the React state rules.
## Contract
Follows the dev-flow contract — see `references/contracts.md`. Key facts:
- Reads `meta.json#stack.framework` and `stack.nextjs_version`. For monorepo, reads `stack.monorepo.web.*`.
- **Refuses** if `stack.framework ∉ {"next", "monorepo"}` or `stack.nextjs_version != "16"`. The principles transfer to other React 19 setups (Remix v3, plain React 19