Разбор алгоритма React Diff

React.js

Роль Диффа

React Diff поможет нам разобраться, что находится в Virtual DOMЧасть, которая действительно изменилась, и выполняйте фактические манипуляции с DOM только для этой части вместо повторного рендеринга всей страницы.

Проблемы с традиционными алгоритмами сравнения

Традиционный алгоритм сравнения использует циклическую рекурсию для поочередного сравнения узлов, сложность — O(n^3), а эффективность низкая.

Стратегия алгоритма React diff

  • Для древовидной структуры (tree diff): игнорируйте межуровневую операцию узлов DOM слоя пользовательского интерфейса. (небольшое количество)
  • Для diff компонентов: иметь то же самоеДобрыйДва компонента генерируют похожие древовидные структуры с разнымиДобрыйДва компонента , генерируют разные структуры свойств.
  • Для element-diff: для группы узлов на одном уровне используйтеуникальностьидентификатор различия (ключевой атрибут)

Особенности дерева diff

  • React выполняет иерархический обход виртуального дерева DOM с помощью updateDepth.

  • Два дерева сравнивают только узлы на одном уровне.Пока узел не существует, узел и все его дочерние элементы будут заменены.удалить полностью, дальнейшее сравнение не производится.

  • Для сравнения всего дерева DOM требуется только один обход.

React diff учитывает толькотот же уровеньПреобразование позиции узла , если это межуровневое изменение позиции, это операция создания узла и удаления узла. То есть тот же узел воссоздается в новой позиции, а узел в исходной позиции удаляется.

Советы: React официально рекомендует не выполнять межуровневые операции над узлами DOM, а скрывать и отображать узлы через CSS, вместо фактического удаления и добавления узлов DOM, поддержание стабильной структуры DOM поможет повысить производительность.

Особенности diff компонентов

  • Для одного и того же типа компонентов сравните виртуальное DOM-дерево в соответствии с исходной стратегией (tree diff).
  • Для одного и того же типа компонента компонент A преобразуется в компонент B. Если виртуальный DOM не меняется, вы можете передатьshouldComponentUpdate()метод, чтобы определить, является ли

Официальная документация React по внедрению shouldComponentUpdate

  • Различные типы компонентов, тогда алгоритм сравнения будет оценивать компоненты, подлежащие изменению, какdirty component, тем самым заменяя все узлы всего компонента.

Даже если компоненты похожи по структуре, пока React считает, что это разные компоненты, он не будет судить, являются ли они компонентами разных типов, и не будет сравнивать их структуры, а удалит компонент и его подкомпоненты и создать новый компонент и узел его подкомпонентов.

Отличительные особенности элементов

Для узлов одного уровня React diff предоставляет три операции с узлами: вставка, перемещение, удаление.

  • Вставка: новый компонент находится не в исходной коллекции, а в совершенно новом узле, и операция вставки выполняется в коллекции.
  • Удалить: компонент уже находится в коллекции, но коллекция была обновлена, и в это время необходимо удалить узел.
  • Мобильный: Компонентыуже существует вВ коллекции и при обновлении коллекции компонент не обновляется, а меняется позиция, например: (A,B,C,D) → (A,D,B,C), если онатрадиционная разницаКогда обнаруживается, что вторая цифра в старом наборе — B, а вторая цифра в новом наборе — D, удалите B, вставьте D, и все последующие узлы должны быть перезагружены, в то время как React diff — путем добавления узлов в тот же слойуникальный ключМы различаем и двигаемся.

Некоторые движущиеся сцены и логика

Тот же узел, другое место

nT73TS.md.jpg

Начать обход по порядку в новой коллекции

  1. B в новом наборе lastIndex (аналогично float) = 0, в старом наборе index = 1, index >lastIndexСчитается, что B не влияет на положение других элементов множества и не перемещается, и тогдаlastIndex = max(index, lastIndex) = 1
  2. A имеет индекс = 0 в старом наборе, в этот моментlastIndex= 1, удовлетворяют индексу lastIndex, затем выполните операцию перемещения на A, в это времяlastIndex = max(Index, lastIndex) = 1
  3. Операции D и B такие же, как и (1), без движения, в это времяlastIndex=max(index, lastIndex) = 3
  4. C и A работают так же, как и (2), чтобы двигаться, в это времяlastIndex = max(index, lastIndex) = 3
Расположение узлов изменилось

nT7GFg.md.jpg

1. В той же ситуации, что и выше, B не движется,lastIndex=1

2. Получить E в новом наборе и обнаружить, что E не существует в старом наборе.lastIndexгде создается Е,lastIndex++

3. Возьмем С в старом наборе, С не двигается,lastIndex=2

4. Возьмите А в старом наборе, переместите А на позицию в новом наборе,lastIndex=2

5. После завершения сравнения всех узлов в новом наборе пройдитесь по старому набору в цикле, чтобы найти узел (D в этом примере), который не существует в новом наборе, но есть в наборе, и удалите узел D. .

Недостатки React diff

nT71w8.md.jpg

В этом примере D напрямую повышается с последней цифры на первую цифру, что приводит кlastIndexНа первом этапе он напрямую обновляется до 3, так что ABC находится в состоянии index последнийУзел повышен доПервыйЕсли рабочая частота высока или количество узлов велико, это повлияет на производительность рендеринга.

резюме

  • Разница между React diff и традиционным diff заключается в том, что React улучшает O (n ^ 3) до O (n) за счет оптимизации.
  • React оптимизирует различия между деревьями, компонентами и элементами тремя способами.
  • Во время разработки старайтесь поддерживать стабильную структуру DOM и сократить операцию перемещения последнего узла в первый, что может оптимизировать производительность рендеринга.

использованная литература

«Погрузитесь в стек React»

Серия анализа исходного кода React - невероятная реакция diff