EngineeringWriting

Optimizing React Re-renders

A practical look at when re-renders actually matter, and when we reach for memoization before understanding the real bottleneck.

Oct 12, 2025
2 min read
Aadarsh Srivastava

The problem with unnecessary re-renders

React's virtual DOM is efficient, but that's not a license to be careless about re-renders. Every one costs CPU cycles, and in a complex app those cycles add up into something a user actually feels.
When a component re-renders, React runs the component function, diffs the new virtual DOM against the old one, and updates the real DOM if anything changed. None of that is free.

Understanding useMemo

useMemo is the first line of defense against an expensive calculation running on every render. It memoizes a computed value and only recalculates when its dependencies change.
javascript
const expensiveValue = useMemo(() => {
return computeExpensiveValue(a, b)
}, [a, b])

useCallback

useCallback does the same thing for functions: it returns a memoized callback that only changes when its dependencies do.
javascript
const handleClick = useCallback(() => {
doSomething(a, b)
}, [a, b])

React Compiler

React Compiler (formerly React Forget) automates a lot of this memoization work, which should cut down on how much manual optimization is necessary. Worth watching, not yet a reason to stop reasoning about renders yourself.

What I actually do

Profile before optimizing. Most re-render problems aren't where you'd guess. Use React DevTools to find the actual source instead of memoizing defensively. Apply useMemo and useCallback where the profiler says to, not everywhere. And keep an eye on where React Compiler lands, since it'll change how much of this is worth doing by hand.