Virtual DOM in React
The Virtual DOM (Virtual Document Object Model) is one of the core concepts behind React's efficient UI updates.
The easiest way to understand it is:
React does not directly manipulate the browser's DOM for every state change. Instead, it creates an in-memory representation of the UI, compares the new representation with the previous one, and updates only the necessary parts of the real DOM.
Let's understand this from the ground up.
1. What is the Real DOM?
DOM stands for Document Object Model.
When the browser loads an HTML page:
<div>
<h1>Hello</h1>
<p>Welcome</p>
</div>
The browser converts this HTML into a tree structure.
Document
|
└── div
|
├── h1
| └── "Hello"
|
└── p
└── "Welcome"
This is the Real DOM.
JavaScript can manipulate this DOM:
document.querySelector("h1").textContent = "Hello React";
The browser then has to process the change and potentially recalculate:
- DOM structure
- CSS styles
- layout
- painting
- compositing
For a small application, this is not a problem.
But imagine a large application with thousands of DOM elements.
2. The Problem with Frequent DOM Updates
Consider:
<div id="app">
<h1>Count: 0</h1>
<p>Welcome to React</p>
<button>Increment</button>
</div>
Suppose clicking the button changes:
Count: 0
to:
Count: 1
Only the <h1> text actually needs to change.
A naive approach might repeatedly manipulate many DOM elements.
React instead maintains an in-memory representation of what the UI should look like.
That's where the Virtual DOM comes into the picture.
3. What is the Virtual DOM?
The Virtual DOM is essentially a JavaScript representation of the UI structure maintained by React.
For example, conceptually:
Virtual DOM
div
├── h1
│ └── "Count: 0"
├── p
│ └── "Welcome to React"
└── button
└── "Increment"
It is not the browser's actual DOM.
It exists in memory.
You can think of it as a lightweight description of the real DOM.
4. React Components Produce a UI Description
Consider this React component:
function App() {
return (
<div>
<h1>Hello</h1>
<p>Welcome to React</p>
</div>
);
}
The JSX:
<div>
<h1>Hello</h1>
<p>Welcome to React</p>
</div>
describes what the UI should look like.
React creates an internal representation of this UI.
Conceptually:
App
|
└── div
|
├── h1
| └── Hello
|
└── p
└── Welcome to React
This representation is used during React's rendering process.
5. What Happens When State Changes?
This is where Virtual DOM becomes particularly important.
Consider:
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<p>Welcome to React</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Initially:
count = 0
The UI is:
div
├── h1
│ └── Count: 0
├── p
│ └── Welcome to React
└── button
└── Increment
Now click the button.
setCount(count + 1);
The state becomes:
count = 1
React renders the component again.
The new UI description becomes:
div
├── h1
│ └── Count: 1
├── p
│ └── Welcome to React
└── button
└── Increment
React now has:
Previous representation
h1
└── Count: 0
New representation
h1
└── Count: 1
React determines that only the text inside the <h1> needs to change.
The actual DOM update is therefore approximately:
Count: 0
↓
Count: 1
The <p> and <button> don't need to be recreated.
6. The Important Process: Render → Compare → Commit
A simplified React update process can be understood as:
State / Props Change
|
v
React Render
|
v
New UI Representation
|
v
Compare with Previous
|
v
Determine Required DOM Changes
|
v
Commit Changes
|
v
Browser UI
These stages are important.
7. Step 1 — State or Props Change
For example:
setCount(1);
React schedules an update.
The component needs to be evaluated again to determine what the UI should look like.
8. Step 2 — React Renders the Component
React calls the component again.
For example:
function Counter() {
const [count, setCount] = useState(0);
return (
<h1>
Count: {count}
</h1>
);
}
After the state change:
count = 1
the component produces:
<h1>Count: 1</h1>
This creates a new UI representation.
9. Step 3 — Reconciliation
React then compares the previous rendered result with the new result.
This process is called reconciliation.
For example:
Previous:
div
├── h1
│ └── Count: 0
├── p
│ └── Welcome
└── button
New:
div
├── h1
│ └── Count: 1
├── p
│ └── Welcome
└── button
React recognizes:
div → unchanged
h1 → unchanged
text → changed
p → unchanged
button → unchanged
Therefore:
Only text node needs updating
This comparison/reconciliation process is a major part of React's update mechanism.
10. Step 4 — Commit
After determining what needs to change, React applies the required changes to the real DOM.
Conceptually:
Virtual representation
|
| "Change Count: 0 → Count: 1"
v
Real DOM
|
v
Browser displays Count: 1
11. Important: Virtual DOM Does NOT Mean "No DOM Manipulation"
This is a common misunderstanding.
React does manipulate the real DOM.
The difference is that React manages those DOM changes for you and tries to make the updates efficient.
So this statement is incorrect:
React never changes the real DOM.
Correct:
React uses its internal representation and reconciliation process to determine the necessary changes to the real DOM.
12. Virtual DOM vs Real DOM
| Real DOM | Virtual DOM |
|---|---|
| Browser-managed | React-managed representation |
| Represents actual page | Represents desired UI |
| Exists in browser | Exists in memory |
| Directly affects displayed page | Used to calculate updates |
| DOM operations can be expensive | Comparison happens in memory |
| Changes affect browser rendering | Changes don't directly affect screen |
13. A Simple Example
Suppose you have:
function App() {
return (
<div>
<h1>Hello</h1>
<p>Welcome</p>
<button>Click Me</button>
</div>
);
}
Think of the UI tree as:
div
├── h1
│ └── Hello
├── p
│ └── Welcome
└── button
└── Click Me
Now change:
<h1>Hello</h1>
to:
<h1>Hello React</h1>
React doesn't need to rebuild everything.
Conceptually:
Before:
div
├── h1 → Hello
├── p → Welcome
└── button → Click Me
After:
div
├── h1 → Hello React
├── p → Welcome
└── button → Click Me
Difference:
h1 text changed
So the real DOM update can be limited to that change.
14. Is the Virtual DOM Actually a DOM?
Strictly speaking, no.
The term "Virtual DOM" can be slightly misleading.
The Virtual DOM isn't another browser DOM.
It is an in-memory representation of UI elements used by React's rendering system.
For example:
Real DOM
Browser
|
└── DOM Nodes
Whereas:
React's internal UI representation
JavaScript Memory
|
└── React Elements / Fiber tree
Modern React's implementation uses a Fiber architecture to represent and process work on the component tree.
15. React Elements vs Virtual DOM
These terms are sometimes used interchangeably, but they're not exactly the same thing.
Consider:
<h1>Hello</h1>
JSX is transformed into JavaScript roughly conceptually like:
React.createElement(
"h1",
null,
"Hello"
);
This creates a React element describing what should be rendered.
React then uses its internal structures, including the Fiber tree, to manage rendering and updates.
So a useful conceptual chain is:
JSX
↓
React Element
↓
React's internal Fiber tree
↓
Reconciliation
↓
Real DOM update
Calling the whole mechanism "Virtual DOM" is common, but technically React's modern implementation is more sophisticated than simply maintaining a cloned DOM tree.
16. What is Fiber?
You will frequently hear React Fiber when studying the Virtual DOM.
Fiber is the architecture React uses to represent components and manage rendering work.
Conceptually:
React Application
|
v
Fiber Tree
|
v
Reconciliation
|
v
Commit
|
v
Real DOM
A Fiber node contains information about a component or DOM element and the work React needs to perform.
For example:
App Fiber
|
└── div Fiber
|
├── h1 Fiber
|
├── p Fiber
|
└── button Fiber
Fiber enables React to break rendering work into manageable units and prioritize work.
This is particularly important for modern React's concurrent rendering capabilities.
17. Reconciliation in More Detail
Suppose the previous UI is:
div
├── h1
├── p
└── button
New UI:
div
├── h1
├── p
├── button
└── footer
React doesn't need to recreate:
div
h1
p
button
It can determine that:
footer
was added.
So conceptually:
Existing DOM
|
+-- div
+-- h1
+-- p
+-- button
+-- footer ← add
18. What Happens If an Element Type Changes?
Suppose:
<div>
Hello
</div>
changes to:
<span>
Hello
</span>
React sees:
div
↓
span
These are different element types.
React generally treats this as a replacement rather than simply changing the tag in place.
Conceptually:
Old
div
└── Hello
New
span
└── Hello
The old subtree can be removed and the new one created.
19. What About Lists?
Lists introduce another important concept: keys.
Consider:
const users = [
{ id: 1, name: "John" },
{ id: 2, name: "David" },
{ id: 3, name: "Sarah" }
];
Rendering:
users.map(user => (
<li key={user.id}>
{user.name}
</li>
))
The key helps React identify elements between renders.
For example:
Previous
1 → John
2 → David
3 → Sarah
New
1 → John
2 → Sarah
3 → David
React can use the keys to understand which logical items correspond to which previous items.
20. Why Are Keys Important?
Without stable keys, React can have difficulty correctly matching list items across updates.
Bad:
users.map((user, index) => (
<li key={index}>
{user.name}
</li>
))
Better:
users.map(user => (
<li key={user.id}>
{user.name}
</li>
))
Especially when items can be:
- inserted
- deleted
- reordered
stable keys are important.
21. Virtual DOM Does Not Mean Every Update Is Automatically Fast
Another common misconception:
"React uses Virtual DOM, therefore React is always fast."
Not necessarily.
React still has to:
- Re-render components
- Build/reconcile the resulting tree
- Determine changes
- Commit required changes
Poor component design can still cause unnecessary work.
For example:
function App() {
const [count, setCount] = useState(0);
return (
<>
<Counter count={count} />
<LargeComponent />
<AnotherLargeComponent />
</>
);
}
If count changes, the parent renders again.
Depending on component structure and optimization, child components may also render again.
That's why React performance techniques include:
React.memo
useMemo
useCallback
lazy
Suspense
code splitting
proper component boundaries
proper keys
These are separate concepts from the Virtual DOM itself.
22. Virtual DOM vs Direct DOM Manipulation
Suppose you're using plain JavaScript:
document.getElementById("count").textContent = count;
You explicitly tell the browser:
Find this DOM element
↓
Change its text
React takes a declarative approach:
<h1>Count: {count}</h1>
You tell React:
"When
counthas this value, the UI should look like this."
React determines how to update the DOM.
This is a fundamental difference.
Imperative
element.textContent = "Count: 10";
You specify how to change the UI.
Declarative
<h1>Count: {count}</h1>
You specify what the UI should look like.
React handles the update mechanism.
23. Real DOM vs Virtual DOM — Example
Imagine a page with 1,000 elements:
Page
│
├── Header
├── Navigation
├── Sidebar
├── Content
│ ├── Article
│ ├── Comments
│ └── Related Articles
│
├── Advertisement
├── Footer
└── ...
Suppose only:
Comment #25
changes.
React's reconciliation process attempts to determine the minimal set of DOM mutations needed.
Conceptually:
1000 UI nodes
|
v
New render
|
v
Compare
|
v
1 relevant change
|
v
Update required DOM node
The important point is not that React compares every DOM node naively. React uses heuristics and its tree structure to make reconciliation practical.
24. Virtual DOM Is Not Faster Than the DOM in Every Situation
This is an important technical point.
The Virtual DOM introduces additional work:
Component render
↓
Create/reconcile representation
↓
Determine changes
↓
Commit DOM changes
If you manually update one DOM node with:
element.textContent = "Hello";
that can be more direct.
So the Virtual DOM isn't simply:
"A faster version of the DOM."
A better statement is:
React's rendering and reconciliation system provides an efficient and predictable way to manage complex UI updates without requiring developers to manually synchronize the DOM.
The advantage becomes particularly useful for large, dynamic applications.
25. Virtual DOM and React's Declarative Model
This relationship is extremely important.
Without React:
State changes
↓
Developer determines
what DOM needs updating
↓
Developer modifies DOM
With React:
State changes
↓
Component renders
↓
React determines required changes
↓
React updates DOM
This makes UI programming significantly more declarative.
26. Complete Flow
You can remember the complete React update process like this:
User Interaction
|
v
Event Handler
|
v
setState()
|
v
State Changes
|
v
Component Render
|
v
New React Element Tree
|
v
Reconciliation
|
Compare Previous/New
|
v
Determine Changes
|
v
Commit
|
v
Real DOM Update
|
v
Browser
|
v
Updated UI
27. A Practical Counter Example
Consider:
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Counter</h1>
<h2>Count: {count}</h2>
<p>This text never changes.</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
export default App;
When:
count = 0
UI:
div
├── h1 → Counter
├── h2 → Count: 0
├── p → This text never changes.
└── button → Increment
After clicking:
count = 1
New UI:
div
├── h1 → Counter
├── h2 → Count: 1
├── p → This text never changes.
└── button → Increment
React identifies:
h1 → unchanged
h2 → text changed
p → unchanged
button → unchanged
Therefore, only the necessary DOM mutation is committed.
28. Very Important Interview Question
"Does React update the Virtual DOM?"
A good answer is:
React creates a new React element tree when a component renders and uses its reconciliation process to compare the new result with the previous one. React's Fiber architecture tracks this work and determines what changes need to be committed to the real DOM.
Avoid saying:
"React directly modifies the Virtual DOM."
That's an oversimplification.
29. Another Common Interview Question
"Why does React use Virtual DOM?"
A strong answer:
React uses an in-memory representation of the UI so that it can reconcile changes before committing them to the browser DOM. This allows React to declaratively manage complex, frequently changing interfaces and minimize unnecessary DOM mutations.
30. Virtual DOM Is Only One Part of React
Don't think of React architecture as:
JSX
↓
Virtual DOM
↓
Browser
A better conceptual model is:
JSX
|
v
React Elements
|
v
Fiber Tree
|
v
Render / Reconcile
|
v
Commit
|
v
Browser DOM
And user interactions can feed back into this:
Browser
|
| User clicks
v
Event Handler
|
v
State Update
|
v
React Render
|
v
Reconciliation
|
v
Commit
|
v
Browser DOM
31. Key Terms You Should Know
When studying React Virtual DOM, understand these terms together:
| Term | Meaning |
|---|---|
| DOM | Browser's document structure |
| Virtual DOM | In-memory conceptual representation of UI |
| React Element | Description of what React should render |
| Render | React calculates what the UI should look like |
| Reconciliation | React determines differences between renders |
| Fiber | React's internal architecture for managing rendering work |
| Commit | Applying required changes to the host environment/DOM |
| Key | Stable identity for elements in lists |
| State | Data that can trigger a re-render |
| Props | Data passed from parent to child |
32. The One Diagram to Remember
STATE / PROPS CHANGE
|
v
React Component
|
v
RENDER
|
v
React Element Tree
|
v
FIBER / WORK
|
v
RECONCILIATION
|
Compare Changes
|
v
MINIMAL UPDATE
|
v
COMMIT
|
v
REAL DOM
|
v
BROWSER UI
In one sentence:
Virtual DOM is an in-memory representation used by React's rendering system to efficiently determine how the UI should change; React reconciles the new result with the previous one and commits the necessary changes to the real DOM.
One important modern nuance: the Virtual DOM should not be described simply as "React copies the entire real DOM and compares the two copies." Modern React uses the Fiber architecture, reconciliation heuristics, and a render/commit model. That distinction is useful both for interviews and for understanding React 18/19-era behavior.