How it works
The explanation, with examples you can run.
Trigger
There are two triggers: the initial root.render(<App />), and a state update (a set function from useState or useReducer, or a context value change). Props are not a trigger of their own: a child gets new props because its parent rendered again.
Render
React calls the component whose state changed. Whatever it returns contains more components, so React calls those, and so on down to host elements like div. By default every component below the update renders again, whether or not its props changed.
import { useState } from "react" function Clock({ label }: { label: string }) { return <p>{label}</p> // rendered again on every click, though label never changes} export function Counter() { const [n, setN] = useState(0) return ( <> <button onClick={() => setN(n + 1)}>Clicked {n} times</button> <Clock label="static" /> </> )}This sounds wasteful, but rendering a component is usually a cheap function call. React renders first so that it can compare; work is only expensive when a component does a lot in its body, or when a huge subtree renders on every keystroke. Then you can skip renders with memoisation.
Commit
With the new tree in hand, React works out what changed (see reconciliation) and applies the changes to the DOM in one go: in the example, only the button's text node. The <p>static</p> element is left alone. This is why focus, scroll position, text selection and half-typed input survive re-renders: the DOM nodes are the same nodes.
After the DOM is updated, React attaches refs and runs layout effects, then the browser can paint. Regular effects (useEffect) usually run after the paint, although for updates caused by a click or keypress React may run them before the paint, so their results are visible together.
Why the split matters
- Rendering can be thrown away. React may render a tree and not commit it: Strict Mode renders twice in development, a transition can be interrupted by an urgent update and restarted, and a tree that suspends may never be shown. Anything you do during render must be safe to repeat or discard.
- The DOM is consistent. All changes from one render are committed together, so the user never sees half an update.
- "Re-render" is not "repaint". A component can render a hundred times without the DOM changing, and that's often fine. Measure with the React DevTools Profiler before optimising.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.