←  Back to blog

The cost of a re-render, measured

Apr 30, 2026 · 3 min read performance react

“Too many re-renders” is the most repeated and least measured claim in frontend. We reach for memo, useMemo, and useCallback on reflex, rarely checking whether the render we’re avoiding cost anything in the first place. So I took a real dashboard — a few thousand DOM nodes, live data, the works — and measured.

What a render actually does

A React render is two phases. The render phase runs your components and diffs the result; it’s pure JavaScript and usually cheap. The commit phase applies changes to the DOM; it’s where the browser does layout and paint, and it’s usually where the time goes.

The mistake is optimizing the first phase to avoid the second — when the second never ran.

// This re-renders on every keystroke...
function Row({ item }: { item: Item }) {
    return <td>{item.label}</td>;
}

// ...but if `label` didn't change, the commit phase is a no-op.
// React still bailed out of touching the DOM. The render was free-ish.

The measurement

I instrumented the dashboard with the Profiler API and recorded actualDuration for every commit during a typical session: filtering, sorting, and a live feed updating once a second.

84% of commits took under 1ms. The expensive 16% were all the same shape: a parent re-rendering a large list where every child genuinely changed.

That reframed the whole problem. memo on the leaf rows did nothing measurable — the rows were changing. What helped was not rendering 2,000 rows at all.

What actually moved the needle

// Isolate high-frequency state so it can't re-render its quiet siblings.
function LiveFeed() {
    const tick = useTick(); // updates every second
    return <Ticker value={tick} />;
}
// <Filters /> lives outside LiveFeed and never sees `tick`.

The folklore that didn’t help

Wrapping every callback in useCallback added code, added allocations for the dependency arrays, and changed no measurement. Same for memoizing components whose props changed every render anyway — you pay for the comparison and still re-render.

The takeaway

Profile before you memoize. The expensive renders are rarely the ones we instinctively reach to prevent; they’re the big commits where the DOM genuinely changed, and the fix is usually “do less work,” not “skip work that was already cheap.” Measure the commit, not your anxiety.

~
Husnul Aman
Full-Stack Developer
Email GitHub
 Keep reading
A Vite config I actually understand toolingvite Type-safe forms without the boilerplate architecturetooling