A re-render means a component function runs again. That’s healthy when data changed. It becomes a problem when parents or context force children to re-run even though their visible output didn’t need to.
One-sentence answer: Keep state local, keep props stable, and only memoize when you’ve confirmed a real cost.
Why it matters
Extra re-renders rarely matter on small screens. On dense dashboards, tables, or animation-heavy UIs, they add up. Understanding causes beats blindly wrapping everything in memo.
Re-render vs DOM update
- Re-render: React calls your component again.
- DOM update: React may still skip touching the DOM if output is the same.
So “it re-rendered” is not automatically “the DOM thrashing.” Still, heavy components (charts, large lists) are worth protecting.
Common causes
- Parent re-renders and passes new object/array/function identities every time
- State updates that don’t change meaningful data (or state living too high)
- Unstable list keys causing remounts that feel like “rerender storms”
- Context whose value object is recreated every render
- Inline props in JSX:
style={{ margin: 8 }},onClick={() => ...}into memoized children
// New object every render → memoized child still re-renders
<Chart options={{ color: "green" }} />How to prevent them (in order)
1. Fix structure first
Move state down. Split components so a frequent update doesn’t sit above a heavy subtree.
2. Stabilize props when a child is memoized
const options = useMemo(() => ({ color: "green" }), []);
const onSelect = useCallback((id: string) => {
setSelectedId(id);
}, []);
return <Chart options={options} onSelect={onSelect} />;3. Memoize expensive pure children
const Chart = memo(function Chart({ options, onSelect }: Props) {
// ...
});memo only helps if props are referentially stable (see also: memo vs useMemo vs useCallback).
4. Be careful with context
Split contexts (data vs dispatch), or memoize the context value. One giant value={{ user, theme, flags }} recreated each render wakes every consumer.
5. Lists
Virtualize long lists when needed; use stable keys so React can reconcile instead of remounting.
What not to do
- Don’t wrap every component in
memo“just in case” - Don’t
useMemotrivial values - Don’t optimize before measuring (React DevTools Profiler is enough to start)
Takeaway
Unnecessary re-renders usually mean unstable props or state that’s too high. Fix data flow first; use memo / useMemo / useCallback as targeted tools, not decoration.