Topics in this subject
React 4 min read Updated 5 Aug 2026

Rendering, Virtual DOM & Reconciliation

Render phase builds and diffs a Virtual DOM; commit phase applies minimal DOM mutations, with keys guiding reconciliation.

Render phase vs commit phase 🎯#

React updates the screen in two distinct phases:

Phase What happens Side effects allowed?
Render React calls your components, builds a new Virtual DOM tree, diffs it against the previous ❌ Must be pure — no DOM writes, no mutations. Can be paused/aborted/restarted
Commit React applies the computed changes to the real DOM, then runs useLayoutEffect, then paints, then useEffect ✅ DOM is live

Because the render phase can run multiple times or be thrown away (concurrent features, Strict Mode double-invoke in dev), rendering must be a pure function with no side effects. 🟢

The Virtual DOM & diffing#

React keeps a virtual tree (plain JS objects). On update it builds a fresh tree and compares node-by-node against the old one, producing the minimal list of real DOM operations. A naive tree diff is O(n³); React uses heuristics to get O(n):

  1. Different element type → tear down the old subtree, build the new one (state is lost).
  2. Same type → keep the DOM node, update only changed attributes/props, recurse into children.
  3. Lists → use keys to match children across renders.
// type changed div→span: React destroys the div subtree and remounts
{isEditing ? <span>{x}</span> : <div>{x}</div>}

Reconciliation & the role of keys 🎯#

Reconciliation is the diffing algorithm. Within a list, React uses key to identify which items are the same across renders, so it can move/update rather than destroy and recreate. Keys must be stable, unique among siblings. Without them React falls back to index matching, causing state/DOM bugs on reorder or insert (see the Lists & Keys topic).

What triggers a re-render ⚠️#

A component re-renders when any of these happen:

  • Its state changes (setState from useState/useReducer).
  • Its props change (because its parent re-rendered).
  • A Context value it consumes changes.
  • Its parent re-renders — by default children re-render too, even if their props are identical.

⚠️ A parent re-render cascades to all descendants unless memoized. Use React.memo, and stabilize props with useMemo/useCallback, to prune unnecessary child renders. (Note: React 19's Compiler can auto-memoize, reducing manual work.)

React Fiber (brief)#

Fiber is React 16+'s reconciler — a reimplementation where the work of rendering is split into small units ("fibers") that can be paused, prioritized, and resumed. This enables concurrent rendering: React can interrupt a low-priority render to handle urgent updates (e.g. typing), then continue. It's the engine behind useTransition, Suspense, and time-slicing.

State change → screen#

flowchart LR
  S["state / props change"] --> R["RENDER phase: call components, build new VDOM"]
  R --> D["diff vs previous VDOM (reconciliation)"]
  D --> C["COMMIT phase: apply minimal DOM mutations"]
  C --> L["useLayoutEffect"]
  L --> P["browser paints"]
  P --> E["useEffect"]

Interview Q&A#

Q1. What is the difference between the render and commit phases? Render builds and diffs the Virtual DOM and must be pure (it can be interrupted/re-run). Commit applies the diff to the real DOM and runs effects; the DOM is live there.

Q2. Why must render be pure / side-effect free? React may call components multiple times or discard a render (concurrent mode, Strict Mode double-invoke). Side effects during render would run unpredictably. Put effects in useEffect.

Q3. What causes a component to re-render? Its own state change, changed props, a consumed Context value changing, or its parent re-rendering. By default children re-render when the parent does.

Q4. What is reconciliation and how do keys help? Reconciliation is React's diffing of old vs new Virtual DOM. Keys let React match list items across renders so it moves/updates existing nodes instead of destroying and recreating them.

Q5. What is Fiber and what does it enable? Fiber is React's reconciler that splits rendering into interruptible units of work, enabling concurrent features like prioritization, time-slicing, useTransition, and Suspense.