JavaScript and React course Β· Module 1: React Basics

Virtual DOM and its advantages

4 min read
In this lesson6

One of React's most innovative features is the concept of Virtual DOM (Document Object Model). To understand its significance, we first need to understand the problem it solves.

The problem with traditional DOM

Imagine the browser's DOM as a huge star map, where every star, planet, and space station must be precisely placed. Every change to this map has a cost: the browser has to recalculate the positions of the objects the change affects.

In the traditional approach, when a user performs an action (e.g., clicks a button), it is up to you to:

  1. Find all the DOM elements affected by the change
  2. Update each of them by hand - or, for convenience, rebuild the whole section of the page (e.g., with innerHTML)

After every change the browser recalculates styles and layout and repaints the changed part of the page. When you rebuild a whole section, it does this for all of its elements, even if only one of them changed.

It's like redesigning the entire spaceship when you just want to change the color of one button on the control panel!

How Virtual DOM works

React introduced a revolutionary approach:

  1. The user performs an action
  2. React creates a new Virtual DOM (a lightweight JavaScript copy of the real DOM)
  3. React compares the previous Virtual DOM with the new one (the "diffing" algorithm)
  4. React updates only those elements of the real DOM that actually changed

It's like having a holographic mockup of the spaceship, where you plan changes and test them before applying them to the real ship. This process is incredibly efficient, especially in complex applications where many elements can change simultaneously.

Virtual DOM in action - example

Consider a simple example: we have a to-do list, and a user just marked one task as completed.

In the traditional approach:

  1. Either you find and update the right list item yourself - and you have to remember every such place in your code
  2. Or you rebuild the whole list (e.g., with innerHTML) - simpler, but the browser then processes every item in the list

With React and Virtual DOM:

  1. React creates a new version of the Virtual DOM with the updated task state
  2. Compares it with the previous version
  3. Finds only one changed element (the task marked as completed)
  4. Updates only that specific element in the real DOM

Virtual DOM implementation details

Virtual DOM operates on several levels:

  1. Element representation - Each JSX element is transformed into a lightweight JavaScript object representing a DOM node
  2. Reconciliation - The process of comparing two Virtual DOM trees and calculating the minimal set of operations needed to update the real DOM
  3. Batching - React groups multiple updates into a single session to minimize the number of operations on the real DOM
1// This JSX code
2<div className="task-list">
3  <Task completed={true} name="Task 1" />
4  <Task completed={false} name="Task 2" />
5</div>
6
7// Is transformed into a structure similar to this (simplified)
8{
9  type: 'div',
10  props: {
11    className: 'task-list',
12    children: [
13      {
14        type: Task,
15        props: { completed: true, name: 'Task 1' }
16      },
17      {
18        type: Task,
19        props: { completed: false, name: 'Task 2' }
20      }
21    ]
22  }
23}

Advantages of Virtual DOM

The advantages of this approach are enormous:

  1. Performance - especially in complex applications where the traditional approach could cause noticeable delays
  2. DOM abstraction - developers can focus on application logic rather than DOM manipulation details
  3. Predictability - easier to track state changes and debug problems
  4. Ease of testing - components can be tested in isolation
  5. Cross-platform - since Virtual DOM is a regular JavaScript object, the same concept can be used on different platforms (Web, Mobile with React Native)

Fiber - the new generation of Virtual DOM

Since React 16, a new implementation of the reconciliation algorithm called Fiber was introduced. This architecture enables:

  • Interruptible updates - long rendering operations can be divided into smaller parts
  • Update prioritization - some updates (e.g., animations) can have higher priority
  • Better error handling
  • Better support for Concurrent Mode

This evolution of Virtual DOM shows how React continually develops its key technologies to meet the challenges of modern web applications.

Code for this lesson: App.jsx
1import React from 'react';
2
3// Component demonstrating traditional DOM
4function TraditionalDOMDemo() {
5  const [updates, setUpdates] = React.useState(0);
6  const [isAnimating, setIsAnimating] = React.useState(false);
7
8  const simulateTraditionalUpdate = () => {
9    setIsAnimating(true);
10    setUpdates(prev => prev + 1);
11
12    setTimeout(() => {
13      setIsAnimating(false);
14    }, 1000);
15  };
16
17  return (
18    <div style={{
19      backgroundColor: '#ffebee',
20      padding: '20px',
21      borderRadius: '8px',
22      border: '2px solid #f44336',
23      margin: '15px 0'
24    }}>
25      <h3 style={{ color: '#c62828', marginBottom: '15px' }}>
26        Traditional DOM (Slow)
27      </h3>
28
29      <div style={{
30        display: 'flex',
31        alignItems: 'center',
32        marginBottom: '15px',
33        gap: '15px'
34      }}>
35        <button
36          onClick={simulateTraditionalUpdate}
37          disabled={isAnimating}
38          style={{
39            padding: '10px 20px',
40            backgroundColor: isAnimating ? '#ccc' : '#f44336',
41            color: 'white',
42            border: 'none',
43            borderRadius: '4px',
44            cursor: isAnimating ? 'not-allowed' : 'pointer'
45          }}
46        >
47          {isAnimating ? 'Updating...' : 'Update DOM'}
48        </button>
49
50        <div style={{
51          padding: '8px 15px',
52          backgroundColor: 'white',
53          borderRadius: '4px',
54          border: '1px solid #ccc'
55        }}>
56          Updates: {updates}
57        </div>
58      </div>
59
60      <div style={{
61        backgroundColor: 'white',
62        padding: '15px',
63        borderRadius: '4px',
64        opacity: isAnimating ? 0.5 : 1,
65        transition: 'opacity 1s'
66      }}>
67        <h4>Traditional update steps:</h4>
68        <ol style={{ color: '#666' }}>
69          <li>Find all elements to change</li>
70          <li>Change each element individually</li>
71          <li>Recalculate styles and layout (reflow)</li>
72          <li>Repaint the changed part of the page (repaint)</li>
73        </ol>
74        {isAnimating && (
75          <div style={{
76            color: '#f44336',
77            fontStyle: 'italic',
78            marginTop: '10px'
79          }}>
80            ⏳ Updating... This can take a while for large pages!
81          </div>
82        )}
83      </div>
84    </div>
85  );
86}
87
88// Component demonstrating Virtual DOM
89function VirtualDOMDemo() {
90  const [updates, setUpdates] = React.useState(0);
91  const [isProcessing, setIsProcessing] = React.useState(false);
92  const [virtualChanges, setVirtualChanges] = React.useState([]);
93
94  const simulateVirtualDOMUpdate = () => {
95    setIsProcessing(true);
96    setVirtualChanges(['Creating Virtual DOM...']);
97
98    setTimeout(() => {
99      setVirtualChanges(['Creating Virtual DOM...', 'Comparing with previous version...']);
100    }, 300);
101
102    setTimeout(() => {
103      setVirtualChanges([
104        'Creating Virtual DOM...',
105        'Comparing with previous version...',
106        'Found 1 change to update'
107      ]);
108    }, 600);
109
110    setTimeout(() => {
111      setVirtualChanges([
112        'Creating Virtual DOM...',
113        'Comparing with previous version...',
114        'Found 1 change to update',
115        'Updating only necessary elements'
116      ]);
117      setUpdates(prev => prev + 1);
118      setIsProcessing(false);
119    }, 900);
120
121    setTimeout(() => {
122      setVirtualChanges([]);
123    }, 2000);
124  };
125
126  return (
127    <div style={{
128      backgroundColor: '#e8f5e8',
129      padding: '20px',
130      borderRadius: '8px',
131      border: '2px solid #4caf50',
132      margin: '15px 0'
133    }}>
134      <h3 style={{ color: '#2e7d32', marginBottom: '15px' }}>
135        React Virtual DOM (Fast)
136      </h3>
137
138      <div style={{
139        display: 'flex',
140        alignItems: 'center',
141        marginBottom: '15px',
142        gap: '15px'
143      }}>
144        <button
145          onClick={simulateVirtualDOMUpdate}
146          disabled={isProcessing}
147          style={{
148            padding: '10px 20px',
149            backgroundColor: isProcessing ? '#ccc' : '#4caf50',
150            color: 'white',
151            border: 'none',
152            borderRadius: '4px',
153            cursor: isProcessing ? 'not-allowed' : 'pointer'
154          }}
155        >
156          {isProcessing ? 'Processing...' : 'Update Virtual DOM'}
157        </button>
158
159        <div style={{
160          padding: '8px 15px',
161          backgroundColor: 'white',
162          borderRadius: '4px',
163          border: '1px solid #ccc'
164        }}>
165          Updates: {updates}
166        </div>
167      </div>
168
169      <div style={{
170        backgroundColor: 'white',
171        padding: '15px',
172        borderRadius: '4px'
173      }}>
174        <h4>Virtual DOM Process:</h4>
175        <ul style={{ color: '#666', minHeight: '100px' }}>
176          {virtualChanges.map((change, index) => (
177            <li key={index} style={{
178              marginBottom: '5px',
179              opacity: 0,
180              animation: 'fadeIn 0.5s forwards',
181              animationDelay: `${index * 0.2}s`
182            }}>
183              {change}
184            </li>
185          ))}
186          {!isProcessing && virtualChanges.length === 0 && (
187            <li style={{ color: '#999', fontStyle: 'italic' }}>
188              Click the button to see the Virtual DOM process in action
189            </li>
190          )}
191        </ul>
192      </div>
193
194      <style>
195        {`
196          @keyframes fadeIn {
197            from { opacity: 0; }
198            to { opacity: 1; }
199          }
200        `}
201      </style>
202    </div>
203  );
204}
205
206// Component demonstrating performance differences
207function PerformanceDifference() {
208  const [itemCount, setItemCount] = React.useState(100);
209  const [items, setItems] = React.useState([]);
210
211  React.useEffect(() => {
212    const newItems = Array.from({ length: itemCount }, (_, i) => ({
213      id: i,
214      name: `Element ${i + 1}`,
215      value: Math.floor(Math.random() * 100)
216    }));
217    setItems(newItems);
218  }, [itemCount]);
219
220  const updateAllItems = () => {
221    setItems(prevItems =>
222      prevItems.map(item => ({
223        ...item,
224        value: Math.floor(Math.random() * 100)
225      }))
226    );
227  };
228
229  return (
230    <div style={{
231      backgroundColor: '#f3e5f5',
232      padding: '20px',
233      borderRadius: '8px',
234      border: '2px solid #9c27b0',
235      margin: '15px 0'
236    }}>
237      <h3 style={{ color: '#7b1fa2', marginBottom: '15px' }}>
238        Virtual DOM Performance Demonstration
239      </h3>
240
241      <div style={{
242        display: 'flex',
243        gap: '15px',
244        marginBottom: '15px',
245        flexWrap: 'wrap',
246        alignItems: 'center'
247      }}>
248        <label style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
249          Number of elements:
250          <input
251            type="range"
252            min="50"
253            max="1000"
254            step="50"
255            value={itemCount}
256            onChange={(e) => setItemCount(Number(e.target.value))}
257            style={{ width: '150px' }}
258          />
259          <span style={{ minWidth: '60px' }}>{itemCount}</span>
260        </label>
261
262        <button
263          onClick={updateAllItems}
264          style={{
265            padding: '10px 20px',
266            backgroundColor: '#9c27b0',
267            color: 'white',
268            border: 'none',
269            borderRadius: '4px',
270            cursor: 'pointer'
271          }}
272        >
273          Update All
274        </button>
275      </div>
276
277      <div style={{
278        display: 'grid',
279        gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))',
280        gap: '8px',
281        maxHeight: '200px',
282        overflow: 'auto',
283        backgroundColor: 'white',
284        padding: '15px',
285        borderRadius: '4px'
286      }}>
287        {items.map(item => (
288          <div
289            key={item.id}
290            style={{
291              padding: '8px',
292              backgroundColor: `hsl(${item.value * 3.6}, 70%, 90%)`,
293              borderRadius: '4px',
294              textAlign: 'center',
295              fontSize: '12px',
296              transition: 'background-color 0.3s'
297            }}
298          >
299            <div style={{ fontWeight: 'bold' }}>{item.name}</div>
300            <div>{item.value}</div>
301          </div>
302        ))}
303      </div>
304
305      <div style={{
306        marginTop: '15px',
307        padding: '10px',
308        backgroundColor: 'white',
309        borderRadius: '4px',
310        fontSize: '14px',
311        color: '#666'
312      }}>
313        <strong>Note:</strong> Even when updating {itemCount} elements,
314        React, thanks to Virtual DOM, smoothly processes changes and updates only
315        those elements that actually changed!
316      </div>
317    </div>
318  );
319}
320
321// Component with interactive process visualization
322function VirtualDOMVisualization() {
323  const [step, setStep] = React.useState(0);
324  const steps = [
325    { title: "Initial State", desc: "We have an existing Virtual DOM" },
326    { title: "State Change", desc: "The user performs an action (e.g. clicks a button)" },
327    { title: "New Virtual DOM", desc: "React creates a new Virtual DOM" },
328    { title: "Diff Algorithm", desc: "React compares the old and new Virtual DOM" },
329    { title: "Minimal Changes", desc: "React identifies the minimal set of changes" },
330    { title: "DOM Update", desc: "Only the necessary elements are updated" }
331  ];
332
333  const nextStep = () => {
334    setStep(prev => (prev + 1) % steps.length);
335  };
336
337  const resetSteps = () => {
338    setStep(0);
339  };
340
341  return (
342    <div style={{
343      backgroundColor: '#fff3e0',
344      padding: '20px',
345      borderRadius: '8px',
346      border: '2px solid #ff9800',
347      margin: '15px 0'
348    }}>
349      <h3 style={{ color: '#f57c00', marginBottom: '15px' }}>
350        Step By Step: How Virtual DOM Works
351      </h3>
352
353      <div style={{
354        display: 'flex',
355        gap: '10px',
356        marginBottom: '20px'
357      }}>
358        <button onClick={nextStep} style={{
359          padding: '10px 20px',
360          backgroundColor: '#ff9800',
361          color: 'white',
362          border: 'none',
363          borderRadius: '4px',
364          cursor: 'pointer'
365        }}>
366          Next Step
367        </button>
368
369        <button onClick={resetSteps} style={{
370          padding: '10px 20px',
371          backgroundColor: '#666',
372          color: 'white',
373          border: 'none',
374          borderRadius: '4px',
375          cursor: 'pointer'
376        }}>
377          Reset
378        </button>
379      </div>
380
381      <div style={{
382        backgroundColor: 'white',
383        padding: '20px',
384        borderRadius: '8px',
385        minHeight: '120px'
386      }}>
387        <div style={{
388          display: 'flex',
389          alignItems: 'center',
390          marginBottom: '15px'
391        }}>
392          <div style={{
393            width: '40px',
394            height: '40px',
395            backgroundColor: '#ff9800',
396            color: 'white',
397            borderRadius: '50%',
398            display: 'flex',
399            alignItems: 'center',
400            justifyContent: 'center',
401            fontWeight: 'bold',
402            marginRight: '15px'
403          }}>
404            {step + 1}
405          </div>
406          <h4 style={{ margin: 0, color: '#333' }}>
407            {steps[step].title}
408          </h4>
409        </div>
410
411        <p style={{ color: '#666', fontSize: '16px', lineHeight: '1.5' }}>
412          {steps[step].desc}
413        </p>
414
415        <div style={{
416          marginTop: '15px',
417          display: 'flex',
418          gap: '5px'
419        }}>
420          {steps.map((_, index) => (
421            <div
422              key={index}
423              style={{
424                width: '12px',
425                height: '12px',
426                borderRadius: '50%',
427                backgroundColor: index <= step ? '#ff9800' : '#ddd',
428                transition: 'background-color 0.3s'
429              }}
430            />
431          ))}
432        </div>
433      </div>
434    </div>
435  );
436}
437
438export default function App() {
439  return (
440    <div style={{
441      fontFamily: 'Arial, sans-serif',
442      maxWidth: '900px',
443      margin: '0 auto',
444      padding: '20px'
445    }}>
446      <header style={{
447        textAlign: 'center',
448        marginBottom: '30px',
449        padding: '25px',
450        background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
451        color: 'white',
452        borderRadius: '12px'
453      }}>
454        <h1 style={{ margin: '0 0 10px 0', fontSize: '2.2rem' }}>
455          Virtual DOM and its benefits
456        </h1>
457        <p style={{ margin: 0, fontSize: '1rem', opacity: 0.9 }}>
458          Discover the secret of React's performance and understand why Virtual DOM
459          is a true revolution in the world of front-end development
460        </p>
461      </header>
462
463      <section style={{ marginBottom: '30px' }}>
464        <h2 style={{
465          color: '#333',
466          borderBottom: '2px solid #667eea',
467          paddingBottom: '10px',
468          marginBottom: '20px'
469        }}>
470          Traditional DOM vs Virtual DOM
471        </h2>
472
473        <TraditionalDOMDemo />
474        <VirtualDOMDemo />
475      </section>
476
477      <VirtualDOMVisualization />
478      <PerformanceDifference />
479
480      <div style={{
481        backgroundColor: '#e3f2fd',
482        padding: '25px',
483        borderRadius: '12px',
484        marginTop: '30px'
485      }}>
486        <h3 style={{ color: '#1976d2', textAlign: 'center', marginBottom: '20px' }}>
487          Key Virtual DOM benefits
488        </h3>
489
490        <div style={{
491          display: 'grid',
492          gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
493          gap: '20px'
494        }}>
495          <div style={{ textAlign: 'center' }}>
496            <div style={{ fontSize: '40px', marginBottom: '10px' }}>β†―</div>
497            <h4 style={{ color: '#1976d2' }}>Performance</h4>
498            <p style={{ margin: 0, color: '#666' }}>
499              Minimal DOM updates = faster applications
500            </p>
501          </div>
502
503          <div style={{ textAlign: 'center' }}>
504            <div style={{ fontSize: '40px', marginBottom: '10px' }}>β—†</div>
505            <h4 style={{ color: '#1976d2' }}>Predictability</h4>
506            <p style={{ margin: 0, color: '#666' }}>
507              Easier change tracking and debugging
508            </p>
509          </div>
510
511          <div style={{ textAlign: 'center' }}>
512            <div style={{ fontSize: '40px', marginBottom: '10px' }}>β—†</div>
513            <h4 style={{ color: '#1976d2' }}>Testability</h4>
514            <p style={{ margin: 0, color: '#666' }}>
515              Components can be tested in isolation
516            </p>
517          </div>
518
519          <div style={{ textAlign: 'center' }}>
520            <div style={{ fontSize: '40px', marginBottom: '10px' }}>●</div>
521            <h4 style={{ color: '#1976d2' }}>Cross-platform</h4>
522            <p style={{ margin: 0, color: '#666' }}>
523              The same concept works everywhere
524            </p>
525          </div>
526        </div>
527      </div>
528    </div>
529  );
530}

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. What is Virtual DOM in React?

  2. 2. What are components in React?

  3. 3. What is the main benefit of Virtual DOM in React?

  4. 4. What does the diffing (reconciliation) algorithm in React do?

Hands-on tasks in the game

  • Click in order

    Arrange the Virtual DOM process in order:

Useful articles