Topics in this subject
React 4 min read Updated 5 Aug 2026

Cheat Sheet

Quick reference — all built-in hooks, JSX rules, effect deps, and a performance checklist.

Built-in hooks#

Hook One-liner
useState Local reactive state; returns [value, setValue]
useReducer State via reducer; for complex/related transitions
useEffect Side effects after paint; cleanup + deps
useLayoutEffect Like useEffect but fires before paint (measure/mutate DOM)
useInsertionEffect Injects styles before layout; for CSS-in-JS libs
useContext Read a context value; subscribes to provider
useRef Mutable box that persists across renders; no re-render
useMemo Memoize an expensive computed value
useCallback Memoize a function identity
useImperativeHandle Customize the ref exposed by forwardRef
useId Stable unique id for a11y/SSR-safe attributes
useTransition Mark updates non-urgent; [isPending, startTransition]
useDeferredValue Defer a value to keep UI responsive
useSyncExternalStore Subscribe to external stores safely (concurrent)
useDebugValue Label custom hooks in DevTools
use (19) Read a promise/context in render; suspends on a promise
useOptimistic (19) Optimistic UI state during async actions
useActionState (19) State bound to a form action [state, action, pending]
useFormStatus (19) Pending/status of the enclosing <form>

JSX rules#

  • Return a single root; use a Fragment <>...</> for siblings.
  • Attributes are camelCase: className, htmlFor, onClick, tabIndex.
  • Expressions in {}; false/null/undefined render nothing (but 0 renders 0).
  • Every list item needs a stable key.
  • Close every tag, including self-closing: <img />, <br />.
  • style takes an object: style={{ color: "red", fontSize: 12 }}.

Controlled input snippet#

const [value, setValue] = useState("");
<input value={value} onChange={(e) => setValue(e.target.value)} />;

// checkbox
<input type="checkbox" checked={on} onChange={(e) => setOn(e.target.checked)} />;

Effect deps rules#

Deps array Runs
omitted After every render
[] Once after mount (cleanup on unmount)
[a, b] On mount + whenever a or b change

🟢 Include every reactive value used inside the effect (props, state, functions). Missing deps → stale closures. Wrap helper functions in useCallback or define them inside the effect. ⚠️ Effects run twice in dev StrictMode (mount→unmount→mount) to surface missing cleanup — this is intentional.

Lifecycle mapping (class → hooks)#

Class Hook equivalent
componentDidMount useEffect(fn, [])
componentDidUpdate useEffect(fn, [deps])
componentWillUnmount cleanup return in useEffect
shouldComponentUpdate React.memo

Render flow#

flowchart LR
  A["State/props change"] --> B["Render (build new tree)"]
  B --> C["Reconcile / diff vs previous"]
  C --> D["Commit DOM changes"]
  D --> E["useLayoutEffect (sync)"]
  E --> F["Browser paint"]
  F --> G["useEffect (async)"]

Performance checklist#

  • ✅ Stable keys (ids, not index).
  • ✅ Derive during render; avoid effects for computed data.
  • ✅ Functional updates setX(prev => ...) to dodge stale closures.
  • React.memo + useCallback/useMemo only where profiled.
  • ✅ Split large contexts; memoize provider value.
  • ✅ Code-split with React.lazy + <Suspense>.
  • ✅ Virtualize long lists (react-window/virtual).
  • ✅ Use useTransition/useDeferredValue for expensive updates.
  • ✅ Keep client components at the leaves (RSC) to shrink JS.

Common patterns#

// Lazy + Suspense
const Chart = React.lazy(() => import("./Chart"));
<Suspense fallback={<Spinner />}><Chart /></Suspense>

// Ref to DOM node
const inputRef = useRef(null);
<input ref={inputRef} />; // inputRef.current.focus()

// Conditional render
{isLoading ? <Spinner /> : <List items={items} />}
{items.length > 0 && <List items={items} />}

// Custom hook
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => { ref.current = value; }, [value]);
  return ref.current;
}

Interview Q&A#

Q1. useEffect vs useLayoutEffect? Both run after render; useEffect fires asynchronously after paint, useLayoutEffect fires synchronously before paint. Use useLayoutEffect to measure/mutate the DOM before the user sees it, else prefer useEffect.

Q2. Why does 0 show up in the UI but false doesn't? React renders numbers, and 0 is a number; false/null/undefined render nothing. So {count && <X/>} prints 0 — guard with {count > 0 && <X/>}.

Q3. What belongs in the dependency array? Every reactive value referenced inside the effect — props, state, and functions/objects derived from them. Omitting them causes stale reads; the exhaustive-deps lint rule enforces this.

Q4. Name a few React 19 hooks. use (read a promise/context in render, suspends), useOptimistic (optimistic UI), useActionState and useFormStatus (form action state/pending). React 19 also auto-memoizes via the Compiler.

Q5. When do you reach for useReducer over useState? When state transitions are complex, interrelated, or the next state depends on the previous in non-trivial ways — a reducer centralizes the logic and makes updates testable and predictable.