Reconciliation & Diffing Algorithm
What is Reconciliation?
Definition:
Reconciliation in React is the process React uses to determine what changes to make in the real DOM by comparing the new Virtual DOM with the previous Virtual DOM snapshot.
How Reconciliation Works (High-Level)
React performs:
- Render Phase — JSX → new Virtual DOM is created.
- Diffing Phase — Compare old and new VDOM trees to find differences.
- Commit Phase — Apply only the minimal changes to real DOM.
What is the Diffing Algorithm
React compares:
Old Virtual DOM tree
vs
New Virtual DOM tree
Node by node, top-down.
It never compares real DOM.
The Key Assumptions React Makes
React assumes:
Assumption 1
Elements of different types produce different trees
<div /> → <span />
→ React throws away the old subtree and builds a new one.
No deep comparison.
Ex:
Old tree:
<div>
├─ <h1>
│ └─ "Title"
└─ <p>
└─ "Hello"
</div>
new tree:
<span>
└─ "Hello"
</span>
What React compares
Old root type: div
New root type: span
Types are different ❌
React's decision
<div> subtree ❌ discard completely
<span> subtree ✅ create from scratch
Visual flow
Old VDOM New VDOM
--------- ---------
<div> !== <span>
├─ h1 └─ "Hello"
└─ p
Assumption 2
Children of the same type can be compared positionally (unless keys exist)
High-level diffing steps
For each node:
- Compare type
- Compare key
- If same → update props
- If different → replace subtree
This is O(1) per node.
List Diffing (Where Complexity Matters)
Without keys
[A, B, C]
[B, A, C]
React compares by index:
A vs B → replace
B vs A → replace
C vs C → reuse
This is fast but inefficient in behavior.
With keys
[A(id=1),B(id=2),C(id=3)]
[B(id=2),A(id=1),C(id=3)]
React:
- Builds a key → index map
- Matches nodes by key
- Reorders efficiently
Time Complexity
Generic tree diff (theoretical)
- O(n³) (too slow)
- Impossible for real-time UI
React diffing complexity
- O(n) in most cases
- O(n) for keyed lists
- O(n) for tree traversal
This is why React scales.
Why React Diffing is Fast in Practice
Because React:
- Does NOT compare subtrees deeply
- Uses identity (
type + key) - Stops early when types differ
- Skips work aggressively
When Diffing Becomes Inefficient
Diffing becomes inefficient when:
- Keys are wrong (index keys)
- Large lists reorder frequently
- Components re-render unnecessarily
- Inline objects/functions cause re-renders
Example of inefficient diffing
items.map((item, index) => (
<Item key={index} {...item} />
))
Comparison of React Architecture
| React Version | Rendering Architecture | What Changed |
|---|---|---|
| ≤ React 15 | Stack Reconciler | Synchronous rendering, non-interruptible, UI updates block main thread |
| React 16 | Fiber introduced | New internal engine, interruptible rendering foundation |
| React 17 | Fiber (legacy behavior) | Same Fiber engine, no breaking behavior changes, upgrade bridge |
| React 18 | Concurrent Fiber | Concurrent rendering enabled, automatic batching, transitions |
| React 19 | Server + Client Fiber | Server Components, Actions, streaming, unified rendering model |
Key Takeaway
Reconciliation is how React efficiently updates the real DOM by diffing old and new Virtual DOM trees. By assuming elements of different types produce different trees and using keys for list identity, React achieves O(n) diffing instead of the theoretical O(n³) — making real-time UI updates practical at scale.