| Need | Hook |
|---|---|
| Remember a value across renders, trigger re-render on change | useState |
| Several related state transitions, or state updated from many places | useReducer |
| Read a value from a distant ancestor without prop drilling | useContext (or use if conditional) |
| Cache an expensive calculation | useMemo |
| Give a function a stable identity | useCallback |
| Persist a value across renders WITHOUT causing re-renders | useRef |
| Synchronize with something outside React (subscription, connection) | useEffect |
| Measure/adjust the DOM before the browser paints (avoid a visible flash) | useLayoutEffect |
| Read a value inside an Effect that must be current but non-reactive | useEffectEvent |
| Mark a state update as low-priority/interruptible | useTransition (or startTransition) |
| Show a value that can lag behind an urgent input | useDeferredValue |
| Form submission state (pending, result) via a reducer | useActionState |
| Show a hoped-for result before an async Action confirms | useOptimistic |
| Read a form's pending status from a nested component | useFormStatus |
| SSR-safe unique ID for accessibility attributes | useId |
| Subscribe to a store outside React, tear-safe | useSyncExternalStore |
| Customize what a parent's ref receives | useImperativeHandle |
| Question | If yes → |
|---|---|
| Does this run because the component is displayed with certain values, not because of one specific click/submit? | Effect |
| Does this run only because the user did something specific right now? | Event handler |
| Can this value be computed from existing props/state at render time? | Neither — compute inline, no Effect/handler needed |
| Does this reset all of a component's state when one prop changes? | Neither — use key instead of an Effect |
| Need | Choice |
|---|---|
| Validate/transform/restrict input as the user types | Controlled (value + onChange) |
| Simple field, read only at submission time | Uncontrolled (defaultValue + read via FormData/ref) |
| Multiple fields that must stay in sync with each other live | Controlled |
| Performance-sensitive form with many fields, minimal live validation | Uncontrolled |
Never mix value and defaultValue on the same element.
| Need | Choice |
|---|---|
| Reads from a database/filesystem, no interactivity | Server Component (default, no directive) |
Uses useState/useEffect/event handlers/browser APIs | Client Component ('use client') |
| Server-only logic a Client Component needs to call | Server Function ('use server') |
| Passing data from Server → Client | Must be serializable (plain objects/arrays/strings/numbers, not functions/class instances) |
useMemo/useCallback/memo: apply only where profiling shows a real cost — not a default wrapper.key for list items: a stable ID from data, never the array index if the list can reorder/insert/delete.useEffect that only calls a state setter derived from other state/props → should be computed inline instead.useState booleans that should never both be true → collapse into one status-like variable.onClick={handler()} instead of onClick={handler} → fires immediately during render, not on click.setX(x + 1) called 3× in one handler expecting +3 → use setX(x => x + 1) instead.exhaustive-deps warning suppressed with a comment → almost always the wrong fix; change the code instead.&& in JSX (count && <p/>) → can render a literal 0; coerce to boolean (count > 0 && <p/>).If the project has React Compiler enabled and the affected code follows the Rules of React, prefer letting it handle memoization automatically — write manual useMemo/useCallback/memo only where profiling still shows a gap, or in a codebase not yet on the compiler.