# How React Virtual DOM Works Under the Hood

React is known for being fast and efficient when updating user interfaces. One of the main reasons behind this is the **Virtual DOM** and React's **reconciliation process**.

But what actually happens when a component updates?

How does React know what to change without rebuilding the entire page?

In this article, we'll walk through React's update lifecycle step-by-step and understand how the Virtual DOM helps React perform efficient UI updates.

* * *

# The Problem: Direct DOM Manipulation Is Expensive

Before understanding the Virtual DOM, we first need to understand the problem it solves.

The browser's **Real DOM (Document Object Model)** represents the entire webpage as a tree structure.

Example:

```html
<body>
  <div>
    <h1>Hello</h1>
    <button>Click Me</button>
  </div>
</body>
```

The browser converts this into a DOM tree internally.

Whenever JavaScript directly updates the DOM:

```javascript
document.getElementById("title").innerText = "Updated";
```

the browser may need to:

1.  Recalculate styles
    
2.  Recalculate layout
    
3.  Repaint the screen
    
4.  Re-render portions of the page
    

These operations become expensive when updates happen frequently.

Imagine an application with hundreds or thousands of UI elements updating repeatedly. Direct DOM manipulation can quickly become a performance bottleneck.

* * *

# Real DOM vs Virtual DOM

## Real DOM

The Real DOM is:

*   The actual browser representation of the page
    
*   Managed by the browser
    
*   Expensive to update frequently
    
*   Causes layout and repaint operations
    

## Virtual DOM

The Virtual DOM is:

*   A lightweight JavaScript representation of the UI
    
*   Stored in memory
    
*   Cheap to create and compare
    
*   Managed by React
    

Instead of updating the Real DOM immediately, React first updates the Virtual DOM and then determines the smallest set of changes needed.

Example Virtual DOM representation:

```javascript
{
  type: "div",
  props: {
    children: [
      {
        type: "h1",
        props: {
          children: "Hello"
        }
      }
    ]
  }
}
```

Think of it as a blueprint of what the UI should look like.

* * *

# Initial Render Process in React

Let's start with the first render.

Component:

```jsx
function App() {
  return <h1>Hello React</h1>;
}
```

When React renders this component:

### Step 1: Component Executes

React calls the component function.

```jsx
App()
```

### Step 2: Virtual DOM Tree Is Created

React creates an in-memory tree representing:

```html
<h1>Hello React</h1>
```

### Step 3: Real DOM Nodes Are Created

React converts the Virtual DOM representation into actual DOM elements.

### Step 4: DOM Is Mounted

React inserts those DOM nodes into the browser page. React uses DOM APIs such as `appendChild()` during the initial render.

At this point:

```text
Component
    ↓
Virtual DOM
    ↓
Real DOM
    ↓
Screen
```

* * *

# What Happens When State Changes?

Consider:

```jsx
function Counter() {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </>
  );
}
```

When the button is clicked:

```javascript
setCount(count + 1);
```

React does **not** directly update the DOM.

Instead, it starts a new render cycle.

* * *

# Step 1: React Triggers a Re-render

A state update tells React:

> "The UI may have changed. Recalculate it."

React executes the component again:

```jsx
Counter()
```

using the updated state value.

* * *

# Step 2: A New Virtual DOM Tree Is Created

Old Virtual DOM:

```html
<h1>0</h1>
```

New Virtual DOM:

```html
<h1>1</h1>
```

React now has:

```text
Old Virtual DOM Tree
          vs
New Virtual DOM Tree
```

* * *

# What Is Diffing?

React now compares both trees.

This comparison process is called **diffing**.

Its goal is simple:

> Find the smallest set of changes required to update the UI.

Instead of rebuilding the entire page, React compares:

```text
Old:
<h1>0</h1>

New:
<h1>1</h1>
```

React notices:

*   Same element type (`h1`)
    
*   Only text content changed
    

Therefore:

```text
Update text only
```

No need to replace the whole element.

This comparison process is part of React's reconciliation algorithm.

* * *

# What Is Reconciliation?

**Reconciliation** is the overall process React uses to update the UI efficiently.

It includes:

1.  Creating a new Virtual DOM tree
    
2.  Comparing it with the previous tree
    
3.  Determining differences
    
4.  Applying minimal changes to the Real DOM
    

In simple words:

> Reconciliation = Comparing old UI and new UI to figure out what actually changed.

* * *

# How React Finds Minimal Changes

React follows several rules while diffing.

## Rule 1: Different Element Types

Old:

```jsx
<h1>Hello</h1>
```

New:

```jsx
<p>Hello</p>
```

Since element types differ:

```text
h1 → p
```

React replaces the entire node.

* * *

## Rule 2: Same Element Type

Old:

```jsx
<button className="blue">
```

New:

```jsx
<button className="red">
```

React keeps the same button element and only updates the changed attribute.

* * *

## Rule 3: List Items Use Keys

Example:

```jsx
items.map(item => (
  <li key={item.id}>{item.name}</li>
))
```

Keys help React identify which items:

*   Were added
    
*   Were removed
    
*   Were moved
    

Without keys, React has a harder time matching elements efficiently.

* * *

# Updating Only Changed Nodes

After diffing, React produces a list of updates.

Example:

```text
Change:
<h1>0</h1>

To:
<h1>1</h1>
```

Required update:

```text
Update text node only
```

React then applies only that change to the Real DOM. It avoids unnecessary DOM operations and updates only the nodes that differ between renders.

* * *

# Why This Improves Performance

The browser's DOM operations are expensive.

Creating a Virtual DOM tree is relatively cheap because it's just JavaScript objects in memory.

React's strategy is:

```text
Many cheap JS operations
            +
Few expensive DOM operations
```

Instead of:

```text
Many expensive DOM operations
```

Benefits:

*   Faster UI updates
    
*   Reduced layout recalculations
    
*   Reduced repainting
    
*   Better performance for complex interfaces
    

* * *

# React Render → Diff → Commit Flow

At a high level, every React update follows this lifecycle:

## 1\. Render Phase

React executes components and creates a new Virtual DOM tree.

```text
Component Function
        ↓
Virtual DOM Tree
```

## 2\. Diff (Reconciliation) Phase

React compares:

```text
Old Tree
     vs
New Tree
```

and calculates the minimal set of updates.

## 3\. Commit Phase

React applies those updates to the Real DOM. During re-renders, React performs only the minimal DOM operations calculated during rendering.

```text
Calculated Changes
        ↓
Real DOM Update
        ↓
Browser Paint
```

Overall flow:

```text
State / Props Change
          ↓
Component Re-renders
          ↓
New Virtual DOM Created
          ↓
Diffing (Reconciliation)
          ↓
Changes Calculated
          ↓
Commit Phase
          ↓
Real DOM Updated
          ↓
UI Updated
```

* * *

# Final Thoughts

React's Virtual DOM is not a replacement for the browser DOM. Instead, it's a lightweight JavaScript representation that helps React determine what actually changed.

Whenever state or props update:

1.  React creates a new Virtual DOM tree.
    
2.  It compares it with the previous tree.
    
3.  Diffing identifies differences.
    
4.  Reconciliation determines minimal updates.
    
5.  React updates only the affected DOM nodes.
    

This approach allows developers to write declarative UI code while React handles efficient DOM updates behind the scenes.

The mental model to remember is:

```text
Render
   ↓
Create New Virtual DOM
   ↓
Compare With Previous Tree
   ↓
Find Differences
   ↓
Apply Minimal Changes
   ↓
Update Real DOM
```

And that's the core idea behind how React's Virtual DOM works under the hood.
