Draft. Paste the full article here in
/keystatic, then turn Draft off. The structure below is scaffolding to delete.
Performance work that starts with useMemo usually ends there too, having fixed nothing. The order matters: measure, find the expensive thing, then reach for a tool — and most of the time the expensive thing isn't a re-render at all.
Measure before you optimise
React DevTools' Profiler records a commit and shows you which components rendered and why. Without that recording, every change you make is a guess.
// React DevTools -> Profiler -> record an interaction.
// Look for: components that re-rendered with identical props,
// and commits that took longer than a frame (16ms).Re-renders are usually not the problem
A re-render is a function call. Thousands of them are cheap. What's expensive is what happens inside — a large list mapping to DOM nodes, a layout thrash, a synchronous parse.
The three that actually cost you
- Unvirtualized long lists — 5,000 rows is 5,000 DOM nodes whether or not React is involved
- Layout thrashing — reading
offsetHeightin a loop forces synchronous reflow - Waterfalling data — sequential fetches that could have been parallel
The Core Web Vitals that move
| Metric | What it measures | Highest-leverage fix |
|---|---|---|
| LCP | Largest contentful paint | Serve the hero image from a CDN, prioritise it |
| CLS | Layout shift | Reserve space for anything that loads late |
| INP | Interaction responsiveness | Yield to the main thread on long tasks |
Ship less JavaScript before you ship faster JavaScript. The fastest code is the code you never sent.
The order to work in
- Profile an interaction a real user would actually perform
- Fix the largest cost you can see
- Re-measure — if nothing moved, revert and try the next one