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 offsetHeight in a loop forces synchronous reflow
  • Waterfalling data — sequential fetches that could have been parallel

The Core Web Vitals that move

MetricWhat it measuresHighest-leverage fix
LCPLargest contentful paintServe the hero image from a CDN, prioritise it
CLSLayout shiftReserve space for anything that loads late
INPInteraction responsivenessYield 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

  1. Profile an interaction a real user would actually perform
  2. Fix the largest cost you can see
  3. Re-measure — if nothing moved, revert and try the next one