JavaScript and React course Β· Module 1: React Basics
Virtual DOM and its advantages
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:
- Find all the DOM elements affected by the change
- 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:
- The user performs an action
- React creates a new Virtual DOM (a lightweight JavaScript copy of the real DOM)
- React compares the previous Virtual DOM with the new one (the "diffing" algorithm)
- 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:
- Either you find and update the right list item yourself - and you have to remember every such place in your code
- 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:
- React creates a new version of the Virtual DOM with the updated task state
- Compares it with the previous version
- Finds only one changed element (the task marked as completed)
- Updates only that specific element in the real DOM
Virtual DOM implementation details
Virtual DOM operates on several levels:
- Element representation - Each JSX element is transformed into a lightweight JavaScript object representing a DOM node
- Reconciliation - The process of comparing two Virtual DOM trees and calculating the minimal set of operations needed to update the real DOM
- 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:
- Performance - especially in complex applications where the traditional approach could cause noticeable delays
- DOM abstraction - developers can focus on application logic rather than DOM manipulation details
- Predictability - easier to track state changes and debug problems
- Ease of testing - components can be tested in isolation
- 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. What is Virtual DOM in React?
2. What are components in React?
3. What is the main benefit of Virtual DOM in React?
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: