← Назад к вопросам

По каким критериям React сравнивает виртуальный DOM с реальным

2.0 Middle🔥 232 комментариев
#React#Архитектура и паттерны

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Механизм сравнения (Diffing) в React

React использует эффективный алгоритм сравнения (Diffing Algorithm), который анализирует различия между предыдущим (старым) виртуальным DOM и новым, вычисленным после изменения состояния компонента. Основная цель — определить минимальный набор операций для обновления реального DOM, что значительно повышает производительность.

Ключевые критерии и стратегии сравнения

1. Сравнение на уровне корневых элементов

React сначала сравнивает корневые элементы двух деревьев. Если тип элемента изменился (например, <div> стал <span>), React уничтожает старое дерево и строит новое с нуля. В реальном DOM это приводит к полной замене узла и всех его потомков.

// Старое дерево
<div>
  <ComponentA />
</div>

// Новое дерево - корневой элемент изменился
<span>
  <ComponentA />
</span>
// React пересоздаст всё дерево в реальном DOM

2. Сравнение атрибутов и свойств

Если тип элемента остался прежним, React сравнивает атрибуты (props) и обновляет только изменённые.

// Старое
<div className="old" title="hello" />

// Новое
<div className="new" title="hello" />
// React обновит только className в реальном DOM

3. Рекурсивное сравнение дочерних элементов

При одинаковых родительских элементах React рекурсивно сравнивает дочерние элементы (children). По умолчанию сравнение идёт по индексу в массиве (первый с первым, второй со вторым и т.д.). Это может быть неэффективно при вставке/удалении элементов в середине списка.

// Пример неэффективного обновления при сравнении по индексу
<ul>
  <li key="A">Item A</li>  // Индекс 0
  <li key="B">Item B</li>  // Индекс 1
</ul>

// После добавления элемента в начало
<ul>
  <li key="C">New Item</li>  // Индекс 0 - будет сравниваться с Item A
  <li key="A">Item A</li>    // Индекс 1 - будет сравниваться с Item B
  <li key="B">Item B</li>    // Индекс 2 - будет удалён
</ul>
// React выполнит больше операций, чем необходимо

4. Использование ключей (Keys)

Ключевая оптимизация! Ключи (key) позволяют React отслеживать идентичность элементов между рендерами. React сопоставляет элементы с одинаковыми ключами, даже если их позиция изменилась, избегая лишних перерисовок.

// Без ключей - неэффективное сравнение по индексу
{items.map((item, index) => 
  <li>{item.name}</li>
)}

// С ключами - эффективное сравнение по идентичности
{items.map(item => 
  <li key={item.id}>{item.name}</li>
)}

Как React определяет, что нужно обновлять

Процесс состоит из нескольких этапов:

  1. Рендер нового виртуального DOM — при изменении состояния/пропсов React создаёт новое дерево React-элементов
  2. Сравнение деревьев — React использует эвристический алгоритм O(n), который предполагает:
    • Два элемента разных типов создадут разные деревья
    • Стабильные ключи помогают сопоставлять элементы между рендерами
  3. Создание "разностной карты" (diff) — React определяет:
    • Какие узлы нужно добавить
    • Какие удалить
    • Какие обновить (изменились пропсы/состояние)
    • Какие переместить (при использовании ключей)
  4. Пакетное обновление реального DOM — все изменения применяются за одну синхронную операцию

Оптимизации, основанные на этом механизме

  • shouldComponentUpdate / React.memo — позволяют пропускать повторный рендер, если пропсы не изменились
  • Стабильные ссылки — использование useCallback и useMemo предотвращает создание новых пропсов-функций
  • Идемпотентность рендера — результат рендера зависит только от пропсов и состояния, что делает сравнение предсказуемым

Пример процесса сравнения

// Компонент до обновления состояния
function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <UserItem key={user.id} user={user} />
      ))}
    </ul>
  );
}

// После добавления нового пользователя React:
// 1. Сравнит <ul> → тип одинаковый
// 2. Проверит ключи дочерних элементов
// 3. Обнаружит новый ключ и добавит только один элемент
// 4. Существующие UserItem не будут перерендерены

Важное ограничение: React не гарантирует сохранение состояния компонентов при изменении их позиции без ключей или при изменении типа компонента.

Этот алгоритм сравнения — фундаментальная причина производительности React, позволяющая создавать сложные интерфейсы без ручной оптимизации манипуляций с DOM.