Concept · Building apps

Rendering and reconciliation

A state change re-runs your component; React diffs the result and touches only what changed.

4 minre-rendervirtual DOMkey propreconciliation

In React, rendering means calling your component function to get a description of the UI. It's not the same thing as updating the DOM. The update has two phases:

  1. Render. React calls the components that need updating. Each one returns JSX, which is a tree of plain objects.
  2. Commit. React compares the new tree with the previous one (reconciliation) and applies only the differences to the real DOM.

Rendering is usually cheap. DOM changes are what's expensive, and reconciliation keeps them to a minimum.

What triggers a render

  • The component's state changes (setState, useReducer dispatch).
  • Its parent re-renders. By default every child re-renders too, whether or not its props changed.
  • A context it reads changes.

Props changing isn't a separate trigger. Props only change because a parent rendered. Each render sees a fresh snapshot of props and state, which is why a setCount(count + 1) called twice in one handler only adds 1. Use the updater form, setCount((c) => c + 1), when the next value depends on the previous one.

How the diff works

React assumes two things, which make the diff O(n) instead of O(n³):

  • A different element type means a different subtree. If <div> becomes <section>, or <Profile> becomes <Settings>, React throws away the old subtree, including all its state, and builds a new one.
  • Keys identify children across renders.
jsx
{todos.map((todo) => <TodoItem key={todo.id} todo={todo} />)}

With stable keys, React can tell that an item moved instead of assuming every item after it changed. With array indexes as keys, inserting at the top shifts every key by one. Each item's state then sticks to the wrong row: a checked checkbox or a half-typed input jumps to its neighbour. Use an ID from the data.

Keys also work as a reset switch. <Editor key={docId} /> remounts the editor with fresh state whenever the document changes.

Before optimizing

  • Most re-renders don't matter. Measure with the React DevTools Profiler before adding memo, useMemo or useCallback. The React Compiler can add those automatically.
  • Move state down to the component that uses it, so fewer components re-render when it changes.
  • Don't store what you can compute. Duplicated state and the effects that sync it are a more common source of bugs and wasted renders than slow components. See derived state.

Learn it in depth