Пошук уроків, статей та іншого контенту
З’ясуємо, як Virtual DOM представляє інтерфейс і чому порівняння дерев допомагає ефективно оновлювати DOM.
Virtual DOM — це програмне представлення інтерфейсу у вигляді JavaScript-структури, яка описує, які елементи потрібно показати користувачу.
Браузер працює зі справжнім DOM — деревом вузлів HTML:
<div>
<h1>Ласкаво просимо</h1>
<button>Натиснути</button>
</div>React не змінює це дерево вручну після кожної зміни стану. Спочатку він створює нове представлення інтерфейсу, порівнює його з попереднім, а потім застосовує до справжнього DOM лише необхідні зміни.
Virtual DOM — це не окремий API браузера і не друге дерево, яке браузер відображає на екрані. Це внутрішня концепція React для опису та оновлення інтерфейсу.
React-компонент повертає JSX:
function Welcome() {
return (
<div>
<h1>Вітаємо!</h1>
<p>Це простий компонент.</p>
</div>
);
}JSX схожий на HTML, але фактично він описує, які React-елементи потрібно створити.
Уявно цей результат можна представити як дерево:
div
├── h1
│ └── "Вітаємо!"
└── p
└── "Це простий компонент."Кожен вузол дерева містить інформацію, зокрема:
тип елемента — div, h1, p;
властивості — наприклад, className або disabled;
дочірні елементи;
текстовий вміст.
React використовує це представлення, щоб зрозуміти, яким має бути інтерфейс.
Розглянемо компонент із лічильником:
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<main>
<h1>Лічильник</h1>
<p>Значення: {count}</p>
<button onClick={() => setCount(count + 1)}>
Збільшити
</button>
</main>
);
}Після натискання кнопки відбувається така послідовність:
Викликається setCount.
React оновлює стан компонента.
Компонент виконується знову та повертає нове дерево елементів.
React порівнює нове дерево з попереднім.
React знаходить, що змінився текст у <p>.
У справжньому DOM оновлюється лише це текстове значення.
Структура main, h1 і button залишається без змін. React не створює заново весь документ через зміну одного числа.
Процес порівняння попереднього та нового представлення називають reconciliation — узгодженням або порівнянням дерев.
Наприклад, до зміни стану React може мати таке дерево:
main
├── h1: "Лічильник"
├── p: "Значення: 0"
└── button: "Збільшити"Після натискання кнопки:
main
├── h1: "Лічильник"
├── p: "Значення: 1"
└── button: "Збільшити"Під час порівняння React бачить:
main залишився тим самим;
h1 залишився тим самим;
текст у p змінився;
button залишився тим самим.
Тому в DOM достатньо змінити текст усередині p.
Якщо змінюється властивість елемента, React оновлює відповідну властивість DOM:
function SaveButton({ isSaving }) {
return (
<button disabled={isSaving}>
{isSaving ? "Збереження..." : "Зберегти"}
</button>
);
}Коли isSaving стає true, React:
змінює текст кнопки;
встановлює disabled.
Інші елементи сторінки не потрібно перебудовувати.
Якщо нове дерево має іншу структуру, React узгоджує її з попередньою:
function Message({ isLoggedIn }) {
if (isLoggedIn) {
return <p>Ви увійшли до системи.</p>;
}
return <button>Увійти</button>;
}Залежно від нового результату React може:
видалити старий DOM-вузол;
створити новий;
оновити його текст або властивості.
Робота зі справжнім DOM може бути дорогою, особливо якщо вручну змінювати багато елементів і підтримувати залежності між ними.
Virtual DOM дає React змогу:
описувати бажаний результат декларативно;
не змінювати DOM вручну в кожному обробнику подій;
визначати, які частини інтерфейсу справді змінилися;
застосовувати до браузера лише потрібні оновлення.
Замість такого підходу:
const title = document.querySelector("h1");
title.textContent = "Нове значення";у React описують інтерфейс через стан:
function Title({ text }) {
return <h1>{text}</h1>;
}Коли text змінюється, React сам узгоджує нове представлення зі справжнім DOM.
Virtual DOM не робить усі оновлення безкоштовними. Під час оновлення React все одно має:
виконати компоненти;
створити нове представлення;
порівняти його з попереднім;
внести зміни до справжнього DOM.
Тому важливо відрізняти два поняття:
повторний виклик компонента — React знову обчислює, що має бути показано;
зміна DOM — React фактично змінює елементи сторінки.
Компонент може бути викликаний повторно, але це не означає, що всі його DOM-елементи будуть створені заново.
Під час порівняння списків React має визначити, який елемент відповідає якому попередньому елементу. Для цього використовують властивість key:
function UserList({ users }) {
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}key має бути:
унікальним серед елементів одного списку;
стабільним між оновленнями;
пов’язаним із сутністю елемента, наприклад user.id.
Завдяки цьому React може зрозуміти:
який елемент залишився;
який змінився;
який було додано;
який було видалено.
{users.map((user, index) => (
<li key={index}>{user.name}</li>
))}Індекс може бути непридатним ключем, якщо елементи списку додаються, видаляються або переміщуються. Тоді позиція елемента змінюється, хоча сама сутність залишається тією самою.
Virtual DOM — це внутрішнє представлення, а не дерево, яке безпосередньо відображає браузер.
React намагається застосувати мінімально необхідні зміни, але результат залежить від структури нового та попереднього дерев. Якщо змінюється велика частина структури, зміни можуть бути масштабнішими.
Повторний рендер компонента не є перезавантаженням сторінки. React оновлює інтерфейс без повного перезавантаження документа.
Ключі потрібні не для оформлення списку, а для правильної ідентифікації його елементів під час порівняння.
Virtual DOM допомагає організувати оновлення інтерфейсу, але продуктивність також залежить від структури компонентів, кількості обчислень і розміру оновлюваного дерева.
Virtual DOM — це JavaScript-представлення інтерфейсу, яке використовує React.
Компонент описує бажаний результат за допомогою JSX.
Після зміни стану React створює нове представлення інтерфейсу.
React порівнює нове дерево з попереднім.
До справжнього DOM застосовуються лише необхідні зміни.
Повторний виклик компонента не означає повне створення DOM заново.
Для списків важливо використовувати стабільні та унікальні key.