Detaillierte Analyse des React Diff-Prinzips

Detaillierte Analyse des React Diff-Prinzips

Bevor wir Diff verstehen, werfen wir einen Blick auf die Struktur des virtuellen DOM von React

Dies ist die HTML-Struktur

<div id="Vater">
  <p class="child">Ich bin Kind p</p>
  <div class="child">Ich bin ein untergeordnetes Div</div>
</div>

Dies ist der JS-Code, wenn React HTML rendert. Sie können es auf Babel ausprobieren.

React.createElement("div", {id: "Vater"}, 
    React.createElement("p", {class: "child"}, "Ich bin Kind p"),             
    React.createElement("div", {class: "child"}, "Ich bin ein untergeordnetes Div")
);

Hieraus ist ersichtlich, dass es sich um eine Baumstruktur handelt.

React erstellt beim Aufrufen der Rendermethode einen Baum (als „pre“ bezeichnet) und gibt beim nächsten Aufruf der Rendermethode einen anderen Baum (als „cur“ bezeichnet) zurück. React vergleicht die Unterschiede zwischen den vorherigen und aktuellen Bäumen, um zu ermitteln, wie die Benutzeroberfläche effizient aktualisiert werden kann, und stellt sicher, dass die aktuelle Benutzeroberfläche mit dem neuesten aktuellen Baum synchronisiert wird.

Um die Benutzeroberfläche effizient zu aktualisieren, schlägt React einen O(n) heuristischen Algorithmus vor, der auf den folgenden zwei Annahmen basiert:

1. Zwei verschiedene Elementtypen erzeugen unterschiedliche Bäume.

2. Entwickler können das Schlüsselattribut festlegen, um dem Renderer mitzuteilen, welche Unterelemente bei verschiedenen Renderings unverändert bleiben können.

Diffing-Algorithmus

Schicht-für-Schicht-Vergleich

Beim Vergleich zweier Bäume vergleicht React diese Schicht für Schicht und vergleicht nur DOM-Knoten innerhalb desselben Farbfelds.

Vergleichen Sie zunächst die Wurzelknoten der beiden Bäume. Verschiedene Arten von Wurzelknoten haben unterschiedliche Formen. Wenn der Stammknoten ein Element eines anderen Typs ist, reißt React den ursprünglichen Baum nieder und erstellt einen neuen. Wenn sich beispielsweise ein Element von <a> zu <img>, von <Article> zu <Comment> oder von <Button> zu <div> ändert, wird ein vollständiger Neuaufbauprozess ausgelöst.

//vor
<div>
    <App/>
</div>
//nach
<p>
    <App/>
</p>

React zerstört die App-Komponente (alle ihre Unterkomponenten werden ebenfalls zerstört) und erstellt eine neue App-Komponente (einschließlich ihrer Unterkomponenten) neu.

Die folgende DOM-Strukturkonvertierung:

React berücksichtigt lediglich die Positionsänderungen von Knoten in derselben Ebene. Für Knoten in unterschiedlichen Ebenen erfolgt lediglich eine einfache Erstellung und Löschung. Wenn der Stammknoten feststellt, dass A in seinem untergeordneten Knoten fehlt, zerstört er A direkt, und wenn D feststellt, dass es einen zusätzlichen untergeordneten Knoten A hat, erstellt er ein neues A als seinen untergeordneten Knoten. Daher ist die eigentliche Operation für diese Strukturtransformation:

A.zerstören();
A = neues A();
A.anhängen(neues B());
A.anhängen(neues C());
D.anhängen(A);

Obwohl dieser Algorithmus etwas „grob“ erscheint, basiert er auf der ersten Annahme: Zwei verschiedene Elementtypen erzeugen unterschiedliche Bäume. Laut der offiziellen React-Dokumentation hat diese Annahme bisher nicht zu ernsthaften Leistungsproblemen geführt. Dies gibt uns natürlich auch einen Hinweis darauf, dass die Aufrechterhaltung einer stabilen DOM-Struktur zur Leistungsverbesserung bei der Implementierung unserer eigenen Komponenten beiträgt. Beispielsweise können wir manchmal bestimmte Knoten über CSS ausblenden oder anzeigen, anstatt DOM-Knoten tatsächlich zu entfernen oder hinzuzufügen.

Vergleichen Sie Komponenten des gleichen Typs

Wenn eine Komponente aktualisiert wird, bleibt die Komponenteninstanz unverändert, aber Änderungen an den Daten im Status oder in den Eigenschaften rufen „Render“ auf, um die untergeordneten Elemente in der Komponente für die Aktualisierung zu ändern.

Vergleichen von Elementen desselben Typs

Beim Vergleich zweier React-Elemente desselben Typs behält React die DOM-Knoten bei und vergleicht und aktualisiert nur die Eigenschaften, die sich geändert haben.

<div className="vor" title="Zeug" />

<div className="nach" title="Zeug" />

React ändert den Klassennamen des Div von vorher nach nachher (ähnlich der Zusammenführungsoperation zum Aktualisieren des Status in React).

Rekursiv auf untergeordnete Knoten

Standardmäßig (Ebene-für-Ebene-Vergleich) durchläuft React beim Rekursivdurchlauf über die untergeordneten Elemente eines DOM-Knotens beide Listen mit untergeordneten Elementen gleichzeitig. Wenn ein Unterschied gefunden wird, wird eine Mutation generiert.

Daher ist der Aktualisierungsaufwand beim Hinzufügen von Elementen am Ende der Liste relativ gering. Zum Beispiel:

<ul>
  <li>Erste</li>
  <li>Sekunde</li>
</ul>

<ul>
  <li>Erste</li>
  <li>Sekunde</li>
  <li>dritte</li>
</ul>

React gleicht zuerst die beiden <li>ersten</li>-Bäume ab, gleicht dann den Baum für das zweite Element <li>zweite</li> ab und fügt schließlich den <li>dritten</li>-Baum des dritten Elements ein.

Fügt man die neuen Elemente lediglich in den Tabellenkopf ein, ist der Update-Overhead relativ groß. Zum Beispiel:

<ul>
  <li>Herzog</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Herzog</li>
  <li>Villanova</li>
</ul>

React erkennt nicht, dass es <li>Duke</li> und <li>Villanova</li> behalten sollte und erstellt jedes Kind neu. Diese Situation kann zu Leistungsproblemen führen.

Schlüssel

Um die oben genannten Probleme zu lösen, hat React das Schlüsselattribut eingeführt. Wenn ein untergeordnetes Element über einen Schlüssel verfügt, verwendet React den Schlüssel, um das untergeordnete Element im alten Baum mit dem untergeordneten Element im neuesten Baum abzugleichen. Das folgende Beispiel verbessert die Effizienz der Baumkonvertierung nach dem Hinzufügen eines Schlüssels:

<ul>
  <li Schlüssel="2015">Herzog</li>
  <li Schlüssel="2016">Villanova</li>
</ul>

<ul>
  <li Schlüssel="2014">Connecticut</li>
  <li Schlüssel="2015">Herzog</li>
  <li Schlüssel="2016">Villanova</li>
</ul>

Jetzt weiß React, dass nur das Element mit dem Schlüssel „2014“ neu ist und die Elemente mit den Schlüsseln „2015“ und „2016“ lediglich verschoben wurden. Daher wird nur das Element mit dem Schlüssel=2014 erstellt und die verbleibenden beiden Elemente werden nicht erstellt.

Daher ist es am besten, den Array-Index nicht als Schlüsselwert zu verwenden, da sich die Reihenfolge des Arrays ändern kann. Am besten verwenden Sie die eindeutige Kennung (ID oder andere Attribute), die von den Daten selbst getragen wird.

1. Die Rolle des Schlüssels im virtuellen DOM:
1). Einfach ausgedrückt: Der Schlüssel ist die Kennung des virtuellen DOM-Objekts und spielt beim Aktualisieren der Anzeige eine äußerst wichtige Rolle.

2). Im Detail: Wenn sich die Daten im Status ändern, generiert React basierend auf den neuen Daten einen neuen virtuellen DOM und führt dann einen Diff-Vergleich zwischen dem neuen virtuellen DOM und dem alten virtuellen DOM durch. Die Vergleichsregeln lauten wie folgt:

a. Derselbe Schlüssel wie im neuen virtuellen DOM befindet sich im alten virtuellen DOM:
(1) Wenn sich der Inhalt im virtuellen DOM nicht geändert hat, verwenden Sie direkt den vorherigen realen DOM
(2) Wenn sich der Inhalt im virtuellen DOM ändert, wird ein neuer realer DOM generiert und ersetzt dann den vorherigen realen DOM auf der Seite.

b. Derselbe Schlüssel wie im neuen virtuellen DOM wird im alten virtuellen DOM nicht gefunden
Erstellen Sie basierend auf den Daten ein neues echtes DOM und rendern Sie es dann auf der Seite

2. Probleme, die bei der Verwendung des Index als Schlüssel auftreten können:
1. Wenn Sie Vorgänge ausführen, die die Reihenfolge der Daten zerstören, z. B. das Hinzufügen oder Löschen von Daten in umgekehrter Reihenfolge:
Es werden unnötige echte DOM-Updates generiert. ==> Der Schnittstelleneffekt ist in Ordnung, aber die Effizienz gering.

2. Wenn die Struktur auch DOM der Eingabeklasse enthält:
Führt zu einem falschen DOM-Update. ==> Mit der Schnittstelle stimmt etwas nicht.
3. Achtung! Wenn es keine reihenfolgezerstörende Operation gibt, wie etwa das Hinzufügen oder Löschen von Daten in umgekehrter Reihenfolge,
Es wird nur zum Rendern der Liste für die Anzeige verwendet. Daher ist es kein Problem, den Index als Schlüssel zu verwenden.

Das Obige ist der detaillierte Inhalt der eingehenden Analyse des React Diff-Prinzips. Weitere Informationen zum React Diff-Prinzip finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Detaillierte Erklärung des virtuellen DOM und des Diff-Algorithmus in React
  • React Diff-Algorithmus-Quellcodeanalyse
  • Detaillierte Erklärung des DOM DIFF-Algorithmus in der React-Anwendung
  • Eine kurze Diskussion zur Analyse des Diff-Algorithmus aus dem React-Rendering-Prozess
  • Beispielimplementierung des React-Diff-Algorithmus

<<:  Lösung für Ubuntu 18.04, das keine Verbindung zum Netzwerk in der virtuellen VMware-Maschine herstellen kann

>>:  Einführung in MySQL-Anweisungskommentare

Artikel empfehlen

Anfänger lernen einige HTML-Tags (2)

Verwandter Artikel: Anfänger lernen einige HTML-Ta...

So implementieren Sie eine geplante Sicherung einer MySQL-Datenbank

1. Erstellen Sie ein Shell-Skript vim backupdb.sh...

Detaillierte Erklärung des Unterschieds zwischen Uniapp und Vue

Inhaltsverzeichnis 1. Einfaches Seitenbeispiel 2....

So verwenden Sie Vue3-Mixin

Inhaltsverzeichnis 1. Wie verwende ich Mixin? 2. ...

Implementierung der Docker-Bereitstellung von Django+Mysql+Redis+Gunicorn+Nginx

I. Einleitung Die Docker-Technologie erfreut sich...

MySQL 8.0.12 Installations- und Konfigurations-Tutorial

Dieser Artikel enthält das ausführliche Tutorial ...

Schritte zum Ausführen von ASP.NET Core im Docker-Container

Es gibt in letzter Zeit zu viel Wissen zu lernen,...

Rendern im Vue-Scaffolding verstehen

Im Vue-Gerüst können wir sehen, dass im neuen Vue...

CSS HACK für IE6/IE7/IE8/IE9/FF (Zusammenfassung)

Seit ich die offizielle Version von IE8.0 install...