Что такое React Reconciliation?

🎯 Зачем спрашивают
Проверяется понимание процесса обновления интерфейса при изменениях состояния или пропсов в React.
 
📝 Ответ
Кратко:
React reconciliation (согласование) — это процесс, с помощью которого React определяет, какие изменения нужно внести в DOM, когда состояние или пропсы компонента обновляются.
 
Подробнее:
Reconciliation — это механизм, с помощью которого React:
  1. сравнивает предыдущее виртуальное дерево (Virtual DOM) с новым (diffing)
  1. определяет минимальный набор изменений
  1. и вносит их в реальный DOM максимально эффективно.
 
React использует эвристический (приближённый) алгоритм:
  • Если тип элемента (div, span, MyComponent) не изменился — React сохраняет DOM-элемент и обновляет только изменившиеся свойства или потомков.
  • Если тип изменился — React удаляет старый узел и создаёт новый.
  • Для списков React использует ключи (key), чтобы понимать, какие элементы добавились, удалились или поменяли порядок.
 
💡
Поэтому использование уникальных key в списках так важно для правильного и эффективного reconciliation.
 
Пример 1 (узлы и текстовые изменения)
import React, { useState } from "react"; function Button({ text = "a" }) { const [txt, setTxt] = useState(text); const changeText = () => { setTxt(txt + txt); }; return <button onClick={changeText}>{txt}</button>; }
После клика вызывается setTxt, React запускает новый рендер.
 
Создаётся новое виртуальное дерево, где <button> теперь содержит другой текст.
Reconciliation сравнивает старое и новое дерево.
  • Находит, что тег <button> тот же.
  • Меняется только текстовый узел внутри него.
В реальном DOM обновляется только текст, остальной элемент остаётся прежним.
Пример 2 (списки и ключи)
import React, { useState } from 'react'; function List({ items = ['a', 'b'] }) { const [list, setList] = useState(items); const rotateList = () => { setList([...list.reverse()]); }; return ( <div> {list.map((txt, id) => ( <div key={id}>{txt}</div> ))} <button onClick={rotateList}>rotate</button> </div> ); }
При вызове .reverse() и setList([...list.reverse()]) новый Virtual DOM содержит <div> в обратном порядке, но с теми же ключами (key={id}).
React сравнивает элементы по ключам:
  • Понимает, что это те же элементы, просто с другим содержимым.
  • Меняет текст внутри, но не переставляет DOM-узлы.
 
Было:
<div key=0> a </div> <div key=1> b </div>
Стало:
<div key=0> b </div> <div key=1> a </div>
 
Если бы ключи были разными (key={txt}), то React переставил бы сами DOM-элементы.
 
⚖️ Компромиссы
✅ Плюсы
❌ Минусы
оптимизация DOM-операций, предсказуемость, изоляция перерисовок.
эвристический алгоритм → не всегда идеально (например, при key-ошибках или тяжёлых поддеревьях).
React не делает глубокое сравнение объектов пропсов → может быть избыточный ререндер (поэтому нужен memo / useMemo).
 
🔎 Встречные вопросы
  • Как React понимает, что компонент нужно перерисовать?
  • Что делает shouldComponentUpdate / React.memo?
  • Чем reconciliation отличается от commit-фазы React?
 
🚩 Красные флаги
  • Ответ ограничивается «React обновляет только изменившиеся части».
  • Никаких упоминаний Virtual DOM или ключей.
  • Упоминание "React полностью перерисовывает компонент при setState" (неверно).
  • Называние diffing = reconciliation (на самом деле reconciliation включает diffing + commit).
 
🛠 Практика
Задача 1
  • Сделай компонент списка с 10 элементами и key={index}.
    • Добавь кнопку «добавить элемент в начало».
    • Посмотри, что произойдёт с ключами и перерисовкой.
  • Переделай key на уникальные id и сравни поведение.
 
📚 Источники / ссылки
  • React v16.0 – React Blog