Overview

This card is the lookup table; patterns and trade-offs are in react-hooks and react-performance. Call hooks only at the top level of a component or custom hook, never in conditions, loops, or nested functions, and name custom hooks useX. The eslint-plugin-react-hooks package enforces both rules.

Core hooks

Use the simplest hook that fits; most state needs only useState.

HookUse forNotes
useState(init)Local stateuseState(() => expensive()) runs the initializer once; setX(prev => prev + 1) when the next value depends on the last.
useReducer(reducer, init)State with several sub-values or transitionsDispatch typed actions; the reducer must be pure.
useRef(init)DOM nodes and mutable values that do not renderChanging .current does not re-render.
useContext(Ctx)Read shared values (theme, auth)Every consumer re-renders when the value changes.
useEffect(fn, deps)Sync with an external systemReturn a cleanup; runs after paint.
useLayoutEffect(fn, deps)Measure layout before paintBlocks painting; use sparingly.
useMemo(fn, deps), useCallback(fn, deps)Cache a value / a function identityNeeded mainly for memo children and effect deps.

Effects

Use effects only to sync with external systems, and always clean up.

DepsRuns
noneAfter every render (rarely right).
[]On mount, and unmount for the cleanup.
[a, b]When a or b changes (compared with Object.is).
useEffect(() => {
  const ctrl = new AbortController();
  fetch(`/api/items?q=${q}`, { signal: ctrl.signal })
    .then((r) => r.json())
    .then(setItems)
    .catch((e) => { if (e.name !== "AbortError") setError(e); });
  return () => ctrl.abort();      // cleanup runs before the next effect and on unmount
}, [q]);

Never make the effect function itself async; call an inner async function.

React 19 hooks and APIs

Use these for async actions, optimistic UI, and effect callbacks.

APIUse for
use(promiseOrContext)Read a promise (with Suspense) or context; may be called conditionally.
useActionState(action, init)Form actions: returns [state, formAction, isPending].
useOptimistic(value)Show an optimistic value while an async action runs.
useTransition()[isPending, startTransition]; mark updates as non-urgent.
useDeferredValue(value)Let a slow subtree lag behind a fast input.
useEffectEvent(fn)Read the latest props or state inside an effect without making them dependencies (React 19.2+); call it only from effects.
useId(), useSyncExternalStore(sub, get)Stable ids for accessibility; subscribe to external stores.

React Compiler 1.0 (stable since October 2025) memoizes components automatically when enabled, so hand-written useMemo and useCallback are then mostly unnecessary.

Gotchas

Avoid these; each causes stale values, extra renders, or loops.

GotchaFix
An object, array, or function created in render as a dependency re-runs the effect every render.Move it outside, memoize it, or depend on primitives.
A callback captures stale values when its deps are missing.List every value it reads, use a functional update, or use useEffectEvent.
Reading or writing ref.current during render breaks purity.Do it in effects and event handlers.
Strict Mode runs effects twice in development.Make cleanup undo setup exactly.
Deriving state from props in an effect adds a render and a bug source.Compute the value during render.
A setState in an effect that depends on that state loops.Check what the effect reads and writes.
A context value rebuilt every render re-renders all consumers.Split contexts or memoize the value.