Chapter 1 of 4
Measure Before Optimising
Why most memoisation is wasted, and how to find the real problem.
React is fast. Most components render in well under a millisecond, and wrapping them in memo costs a comparison plus memory while saving nothing. Optimisation without measurement usually makes code harder to read and no faster.
The React DevTools Profiler
- Open React DevTools and switch to the Profiler tab.
- Press record, perform the slow interaction, press stop.
- The flamegraph shows every component that rendered and how long it took.
- Turn on 'Record why each component rendered' in the settings - it names the prop or state that caused it.
You are looking for two things: a component that renders far more often than it should, and a component that takes a long time on a single render. They have different fixes.
The Profiler component
For measurements in code - in tests, or reported to analytics - wrap a subtree in <Profiler>.
import { Profiler } from "react";
function onRender(id, phase, actualDuration) {
// phase is "mount" or "update"
console.log(id, phase, actualDuration);
}
<Profiler id="ProductList" onRender={onRender}>
<ProductList products={products} />
</Profiler>Rendering is often not the bottleneck
- A large JavaScript bundle delays the first render more than any component ever will.
- Unoptimised images usually dominate real-world page load.
- A slow API request cannot be memoised away.
- A layout thrash - reading and writing the DOM in a loop - can be far slower than any React work.