react-patterns
React patterns, senior
You can already build with React — now learn the patterns seniors reach for: composition, state architecture, the server/client boundary, Suspense, and the anti-patterns to refactor away, so components stay simple as they scale.
Start track → 00
Start here
A React pattern is a named, reusable solution to a recurring component-design problem, all descending from UI = f(state). This track assumes React fundamentals and teaches the patterns — with their failure modes — that keep components simple as an app scales. 01
Composition
Components combine by composition, not inheritance: children and slots invert control so the parent supplies content and the component supplies structure. Prop drilling is fine for a few levels — reach for more only when it actually hurts. 02
Compound components
Compound components share implicit state via a private context, giving consumers layout freedom while the parent owns behavior. Support both controlled and uncontrolled modes, and reserve the pattern for reusable widgets, not fixed one-offs. 03
Render props & headless
Render props and headless components separate behavior from presentation; the custom hook is their modern successor for logic reuse — you get state, handlers, and accessibility, and supply your own markup. 04
Custom hooks
A custom hook names and isolates a slice of stateful logic for reuse and testing — extract on real duplication or a clear concept, design its deps and cleanup as a contract, and don't extract a single-caller wrapper. 05
State colocation & lifting
Put state as low as it can go and lift only when truly shared; derive what you can instead of storing it; and keep shareable, navigational state in the URL. 06
Context, done right
Context fits low-frequency, widely-read state; split fat contexts and separate state from dispatch to shrink the re-render blast radius; pair it with a reducer for cross-cutting state with real transitions. 07
External state & stores
Reach for an external store only when lifting and context stop scaling; use selectors to subscribe to just the slice you need (and avoid tearing), and useSyncExternalStore to bridge any external source safely. 08
Effects, disciplined
useEffect is for synchronizing with external systems, not reacting to state; most effects can be deleted (derive instead), and every one that stays must clean up and avoid stale closures. 09
Render performance
Don't memoize by default — profile first; memo, useMemo, and useCallback only help as a system, and stable, unique keys prevent both wasted renders and state-corruption bugs. 10
Server/client boundary
Server Components are the default; push 'use client' to the interactive leaves, pass only serializable props across the boundary, and keep data access and secrets server-only. 11
Suspense & boundaries
Place Suspense close to where data is needed and pair every boundary with an error boundary; use transitions and deferred values to keep the UI responsive under heavy updates. 12
Forms & actions
Default to uncontrolled inputs with FormData and control only when the value drives the UI; React 19 form actions plus useActionState handle pending and errors, and useOptimistic makes mutations feel instant. 13
Data-fetching patterns
Fetch on the server (RSC) for initial data and reach for a query library when you need client cache, dedupe, and mutations; never copy server state into client state, and load independent data in parallel. 14
React anti-patterns
God components, prop drilling, effects that mirror derived state, context misuse, and index keys are the React anti-patterns — fix each with the matching pattern, without over-correcting into a global store or random keys. 15
Capstone: refactor a React feature
Bring it together on a messy React feature: inventory the pattern-smells, refactor incrementally applying composition, hooks, state, and boundaries, and measure that re-renders dropped and the next change got local.Git, from zero to senior
Start having never run `git init`. Finish able to branch, rebase, recover lost work, rewrite history — including changing a commit's author — and run the branching workflow a real team ships on.