Как React определяет, какие DOM узлы нужно менять?
Основы React
React определяет изменяемые узлы алгоритмом reconciliation: сравнивает новое дерево элементов с предыдущим и помечает к обновлению только места реальных отличий.
Эвристики сравнения (O(n))
Честное сравнение деревьев — O(n³); React сводит к линейному трём допущениям:
Сравнение по уровням: деревья обходятся параллельно сверху вниз; узлы сравниваются с узлами той же позиции (перемещения между уровнями не ищутся).
Тип узла решает всё:
- Разные типы (
div→section,UserCard→AdminCard): старое поддерево удаляется целиком (с размонтированием и потерей state), новое строится с нуля — вглубь React даже не смотрит. - Тот же DOM-тип: узел сохраняется; сравниваются атрибуты — в список правок попадают только отличия (className изменился — обновить одно свойство).
- Тот же тип компонента: экземпляр и state сохраняются, компонент вызывается с новыми props, рекурсия продолжается по его результату.
key для списков: дети сопоставляются не по позиции, а по ключу — React отличает перемещение (переиспользовать узел, переставить) от добавления/удаления.
Результат
После обхода накоплен точный список эффектов: «у этого узла обновить textContent, этот вставить, этот удалить». Он применяется к DOM в commit-фазе одним пакетом.
Практические следствия
- Стабильные типы: компонент, объявленный внутри рендера родителя, — каждый раз «новый тип» → постоянное пересоздание.
- Стабильные key из данных, иначе state элементов «переезжает».
- Смена типа обёртки сбрасывает state всего поддерева.
Коротко для собеседования
Через reconciliation: параллельный обход старого и нового дерева по уровням; разные типы узлов — пересоздание поддерева, тот же тип — точечное обновление отличающихся атрибутов и рекурсия вглубь, списки — сопоставление по key. Итог — минимальный список правок для commit-фазы за O(n).