React's Render Cascade and the One Hook That Stops It
Unnecessary re-renders are the most common React performance tax, and the memo/useCallback pairing is the standard prescription. Misapplying either tool—or skipping useCallback when callbacks hit memo boundaries—leaves optimization on the table and trains developers to ignore real render waste.
React's default behavior re-renders every child when a parent updates, a conservative strategy that often wastes cycles. While React.memo can block re-renders by shallow-comparing primitive props, it fails when a function prop gets a new reference on every render. useCallback caches a function instance and only replaces it when declared dependencies change, closing the reference-drift loophole.
The fix is a two-part mechanism: memo decides whether a child should render, and useCallback ensures the props memo inspects remain referentially stable. Without both, passing callbacks to memo-wrapped components provides no optimization benefit.
A guiding principle emerges: apply useCallback only when a function crosses a memo boundary. Native DOM handlers don't need it, and premature wrapping adds complexity without measurable gain.
The article frames React performance work as preventing renders, not accelerating them, which shifts the optimization mindset from micro-benchmarks to structural waste elimination.
Treating useCallback and React.memo as a 'symbiotic pair' clarifies why developers who adopt memo without useCallback see no gains and then dismiss both tools.
The 'soul-searching question'—does this actually cause lag?—is a practical litmus test that many performance guides omit, yet it prevents the most common over-optimization mistake in React codebases.