Virtual DOM
What is Virtual DOM?
The Virtual DOM is a lightweight JavaScript representation of the Real DOM. It's an abstraction that allows frameworks to optimize DOM updates by calculating the minimal set of changes needed.
Try Virtual DOM Concept
Code Editor
Console Output
Click "Run" to execute your code...
Example 1: Virtual DOM Concept
// Virtual DOM is a JavaScript object representation of the DOM
// Example structure:
const virtualDOM = {
type: 'div',
props: {
id: 'container',
className: 'main'
},
children: [
{
type: 'h1',
props: {className: 'title'},
children: ['Hello World']
},
{
type: 'p',
props: {},
children: ['This is a paragraph']
}
]
};
// This represents:
// <div id="container" class="main">
// <h1 class="title">Hello World</h1>
// <p>This is a paragraph</p>
// </div>
// In React JSX:
// const element = (
// <div id="container" className="main">
// <h1 className="title">Hello World</h1>
// <p>This is a paragraph</p>
// </div>
// );
// React.createElement creates the virtual DOM object:
const reactElement = React.createElement(
'div',
{ id: 'container', className: 'main' },
React.createElement('h1', { className: 'title' }, 'Hello World'),
React.createElement('p', null, 'This is a paragraph')
);Example 2: Simple Virtual DOM Implementation
// Creating virtual DOM elements
function createElement(type, props, ...children) {
return {
type,
props: props || {},
children: children.flat()
};
}
// Rendering virtual DOM to real DOM
function render(vNode) {
// Handle text nodes
if (typeof vNode === 'string') {
return document.createTextNode(vNode);
}
// Create element
const element = document.createElement(vNode.type);
// Set props
Object.keys(vNode.props).forEach(key => {
if (key === 'className') {
element.className = vNode.props[key];
} else if (key.startsWith('on')) {
// Handle events: onClick -> click
const event = key.substring(2).toLowerCase();
element.addEventListener(event, vNode.props[key]);
} else {
element.setAttribute(key, vNode.props[key]);
}
});
// Render children
vNode.children.forEach(child => {
element.appendChild(render(child));
});
return element;
}
// Usage
const vApp = createElement(
'div',
{ id: 'app', className: 'container' },
createElement('h1', {}, 'Virtual DOM Example'),
createElement('p', {}, 'This is rendered from virtual DOM'),
createElement('button',
{ onClick: () => console.log('Clicked!') },
'Click Me'
)
);
// Render to real DOM
// const app = render(vApp);
// document.body.appendChild(app);Example 3: Diffing Algorithm Concept
// Simple diff algorithm to find changes
function diff(oldVNode, newVNode) {
// Different types - replace
if (oldVNode.type !== newVNode.type) {
return { type: 'REPLACE', newVNode };
}
// Text node changed
if (typeof oldVNode === 'string' && oldVNode !== newVNode) {
return { type: 'TEXT', newVNode };
}
// Check props changes
const propsPatches = diffProps(oldVNode.props, newVNode.props);
// Check children changes
const childrenPatches = [];
const maxLength = Math.max(
oldVNode.children.length,
newVNode.children.length
);
for (let i = 0; i < maxLength; i++) {
childrenPatches.push(
diff(oldVNode.children[i], newVNode.children[i])
);
}
return {
type: 'UPDATE',
propsPatches,
childrenPatches
};
}
function diffProps(oldProps, newProps) {
const patches = [];
// Find removed or changed props
Object.keys(oldProps).forEach(key => {
if (!(key in newProps)) {
patches.push({ type: 'REMOVE', key });
} else if (oldProps[key] !== newProps[key]) {
patches.push({ type: 'UPDATE', key, value: newProps[key] });
}
});
// Find added props
Object.keys(newProps).forEach(key => {
if (!(key in oldProps)) {
patches.push({ type: 'ADD', key, value: newProps[key] });
}
});
return patches;
}
// Example usage
const oldTree = {
type: 'div',
props: { className: 'old' },
children: [
{ type: 'h1', props: {}, children: ['Old Title'] }
]
};
const newTree = {
type: 'div',
props: { className: 'new' },
children: [
{ type: 'h1', props: {}, children: ['New Title'] },
{ type: 'p', props: {}, children: ['New paragraph'] }
]
};
const patches = diff(oldTree, newTree);
console.log('Changes:', patches);Example 4: Virtual DOM Benefits
// Without Virtual DOM (Direct DOM manipulation)
function updateWithoutVirtualDOM(items) {
const list = document.getElementById('list');
// Clear and rebuild entire list (inefficient!)
list.innerHTML = '';
items.forEach(item => {
const li = document.createElement('li');
li.textContent = item;
list.appendChild(li);
});
}
// With Virtual DOM (React-like)
function updateWithVirtualDOM(items) {
// Create virtual representation
const virtualList = {
type: 'ul',
props: { id: 'list' },
children: items.map(item => ({
type: 'li',
props: {},
children: [item]
}))
};
// React does this internally:
// 1. Compare old virtual DOM with new virtual DOM
// 2. Calculate minimal changes (diff)
// 3. Apply only those changes to real DOM
return virtualList;
}
// Performance comparison
console.time('Without Virtual DOM');
for (let i = 0; i < 100; i++) {
updateWithoutVirtualDOM(['item1', 'item2', 'item3']);
}
console.timeEnd('Without Virtual DOM');
// Virtual DOM frameworks are faster because:
// 1. Batch DOM updates
// 2. Minimize reflows and repaints
// 3. Only update what changed
// 4. Can prioritize updates (React Fiber)
// Example: Updating 1000 items
const largeList = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);
// Direct DOM: Clears and rebuilds all 1000 items
// Virtual DOM: Only updates the items that changedExample 5: React Virtual DOM in Action
// React component using Virtual DOM
function TodoList() {
const [todos, setTodos] = React.useState([
{ id: 1, text: 'Learn React', done: false },
{ id: 2, text: 'Build app', done: false }
]);
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
));
};
// When state changes:
// 1. React creates new virtual DOM
// 2. Compares with previous virtual DOM (reconciliation)
// 3. Calculates minimal changes
// 4. Updates only changed parts in real DOM
return (
<ul>
{todos.map(todo => (
<li key={todo.id} onClick={() => toggleTodo(todo.id)}>
<span style={{ textDecoration: todo.done ? 'line-through' : 'none' }}>
{todo.text}
</span>
</li>
))}
</ul>
);
}
// When you toggle a todo:
// - React creates new virtual DOM with updated todo
// - Diffs against old virtual DOM
// - Finds only that one <li> changed
// - Updates only that <li> in real DOM
// - Other <li> elements are not touched!
// Keys help React identify which items changed
// Bad (without keys):
// todos.map(todo => <li>{todo.text}</li>)
// React can't track which item is which
// Good (with keys):
// todos.map(todo => <li key={todo.id}>{todo.text}</li>)
// React knows exactly which item changed
// Virtual DOM enables:
// - Declarative UI (describe what you want, not how to build it)
// - Efficient updates (minimal DOM manipulation)
// - Cross-platform rendering (React Native uses same concept)
// - Time-travel debugging
// - Server-side renderingKey Points
- Virtual DOM is a JavaScript representation of the Real DOM
- Enables efficient updates by calculating minimal changes (diffing)
- Reduces expensive DOM operations (reflows, repaints)
- Allows batch updates for better performance
- Used by React, Vue, and other modern frameworks
- Trade-off: Additional memory for virtual tree vs faster updates
- Not always faster than direct DOM (depends on use case)