How I Cut Unnecessary React Re-renders by 40%
On a recent client dashboard, a handful of components were re-rendering on nearly every keystroke and network tick. After a focused optimisation pass, I reduced unnecessary re-renders by roughly 40% and measurably improved Core Web Vitals. Here is the exact playbook I used.
1. Measure before you touch anything
Guessing is the enemy of performance work. I always start with the React DevTools Profiler, recording a real interaction and looking for components that render far more often than they should — and how long each render costs.
2. Split global state by concern
A single giant Context that holds everything means every consumer re-renders when any slice changes. I move volatile, frequently-updated state into Zustand stores with selectors, so a component only subscribes to the exact field it reads:
const name = useUserStore((s) => s.name);
// re-renders only when `name` changes, not the whole storeContext still has its place for stable, rarely-changing values (theme, auth user) — the key is matching the tool to the update frequency.
3. Memoize deliberately, not everywhere
React.memo, useMemo, and useCallback are scalpels, not blankets. I apply them at the boundaries the profiler flags — typically list items and expensive children that receive stable props — and verify the win in the profiler rather than assuming it.
4. Stabilise props and identities
A new object or inline function created on every render breaks memoization downstream. Hoisting constants, memoizing derived data, and keeping callback identities stable is often where the biggest, cheapest wins hide.
The takeaway
Performance work is a loop: measure, change one thing, measure again. Selector-based state, targeted memoization, and stable identities did most of the heavy lifting here — without rewriting a single feature.