Basic Docs
reactperformance

React Rendering Pipeline

How React renders components — from trigger to paint — and how to optimize it.

Render vs Commit

React splits updates into two distinct phases. Understanding the boundary helps you predict when side effects run and when the DOM actually changes.

Trigger
Render
Reconciliation
Commit
Paint
React Render Pipeline
1
Trigger
State, props, or context change
2
Render
Component functions called
3
Reconcile
New vs previous VDOM diff
4
Commit
DOM mutations applied
5
Paint
Browser draws to screen

The Render phase is pure and may be interrupted — React calls your component functions and builds a new virtual DOM tree. The Commit phase is synchronous and side-effect safe — React applies the minimal set of DOM mutations, then fires useLayoutEffect and useEffect.

iConcurrent Mode
In React 18+, the render phase can be paused, resumed, or abandoned. Never put side effects in the render phase — only in effects or event handlers.

Virtual DOM & Diffing

React maintains a lightweight in-memory representation of the UI called the Virtual DOM. On each render, React diffs the new tree against the previous one to compute the minimal DOM changes needed.

Reconciliation
Same type → update existing DOM node
Different type → unmount old, mount new subtree
Same key → same identity across renders
New key → unmount old, mount fresh instance
List without keys → O(n³) diff; always add keys
React's Internal Layers
Real DOM
Browser document tree
Virtual DOM
In-memory UI representation
Fiber Tree
React's internal work units
Your Components
JSX you write
Keys are identity, not order
Keys tell React which element is which across renders. Use stable IDs from your data — never array indices for dynamic lists, as it breaks diffing and causes subtle state bugs.

When Does React Re-render?

A component re-renders whenever React needs to check if its output has changed. Knowing the exact triggers prevents unnecessary renders and state bugs.

useState
Calling the setter function schedules a re-render.
useReducer
Dispatching an action triggers the reducer and re-render.
Props change
When a parent re-renders, children receive new props and re-render too.
Context update
Any component consuming a context re-renders when that context value changes.
forceUpdate
Class component escape hatch; rarely needed in function components.
Key change
Changing the key prop unmounts and remounts the component entirely.
Re-render triggers and memoization
// Re-render triggers

// 1. State change
const [count, setCount] = useState(0);
setCount(1); // triggers re-render

// 2. Props change
<MyComponent value={newValue} /> // parent re-renders → child re-renders

// 3. Context change
const theme = useContext(ThemeContext); // re-renders when context value changes

// Prevent unnecessary re-renders
const MemoComponent = React.memo(MyComponent);
const value = useMemo(() => expensive(a, b), [a, b]);
const handler = useCallback(() => doSomething(), []);

Optimization Tips

Most React apps do not need aggressive memoization. Start by profiling, then apply targeted fixes. Over-optimizing untouched code is a common source of bugs.

1
Memoize expensive computations
Wrap costly derived values in useMemo so they only recompute when their dependencies change, not on every render.
2
Stabilize callback references
Use useCallback for event handlers passed as props so child components wrapped in React.memo skip re-renders.
3
Wrap pure components with React.memo
React.memo does a shallow prop comparison and bails out of rendering if props are identical. Only apply where profiling shows a real benefit.
4
Split context by concern
Avoid putting fast-changing and slow-changing values in the same context. Separate them so only affected consumers re-render.
5
Profile before optimizing
Use React DevTools Profiler to identify actual bottlenecks. Premature memoization adds complexity without measurable gain.
!Avoid premature optimization
Every useMemo and useCallback has a memory and bookkeeping cost. Measure with React DevTools Profiler first — if a component is not a measured bottleneck, leave it alone.
Built: 4/8/2026, 12:01:11 PM