В продолжение к посту как работает React и его алгоритм Reconciliation хочется рассказать про допущения этого алгоритма. Допущения алгоритма Reconciliation - это те условия, которые нам как разработчикам необходимо выполнять, чтобы React рендерил компоненты оптимизировано и без пролагивания UI.
Для начала давайте поймем, какая сложность алгоритма сравнения деревьев (Virtual DOM) у React? Алгоритм React это делает за O(N), т.е. сложность линейная. В то время как браузерное API сравнивает DOM-деревья за O(N^3).
И чтобы React продолжал выполнять свою работу за O(N), необходимо знать следующее.
1️⃣ изменился тип узла ==> происходит создание нового дерева.
Допустим, у нас было такое дерево,
<main>
<h1>Users</h1>
<UsersList />
</main>
а после обновления стало таким.
<section>
<h1>Users</h1>
<UsersList />
</section>
Как мы видим, тег main изменился на section. При этом контент внутри этого элемента остался без изменений. Но React удалит и заново создаст все узлы, которые начинаются с main и идут глубже, так как у узла изменился type. Был type: 'main', а стал type: 'section'.
2️⃣ изменился key узла ==> происходит создание нового дерева.
key - полезный инструмент в React. Он позволяет оставлять нетронутыми конкретные узлы между рендерами. Вы точно использовали key при работе со списками.
<div>
{users.map((user) => (
<UserItem key={user.id} id={user.id} name={user.name} />
))}
</div>
Даже если из списка удалить какой-нибудь элемент, то остальные останутся нетронутыми. React сверит их ключи до и после изменения. И если ключи равны, то элемент не будет создан заново.
Более наглядный пример. В коде ниже у компоненты Content произойдет размонтирование и после монтирование. Так как при изменении checked изменился key.
<div className="App">
{checked ? <Content key="1" /> : <Content key="2" />}
</div>
Но при этом, если бы key остался одинаковым между рендерами, то никакого размонтирования не произошло. Просто случилось бы обновление компонента Content.
3️⃣ изменился атрибут узла ==> обновляется только измененный атрибут, создание нового дерева не происходит
Допустим у нас есть следующий JSX.
<div data-testid={isVisible ? 'content-visible' ? 'content-hidden'}>
<UsersList />
</div>
Как мы видим, у div меняется только атрибут data-testid в зависимости от состояния isVisible. В таком случае создание нового дерева и размонтирование всех дочерних узлов div НЕ произойдет. Потому что изменение атрибута не вызывает создание нового дерева.
P.S. Ставь 🔥, если было полезно! Больше про advanced-темы в React можно найти в закрепленном посте.