So starten Sie schnell mit VUE3.0: Erste Schritte
In diesem Tutorial erfahren Sie, wie Sie Memoization in React implementieren. Die Memoisierung verbessert die Leistung, indem die Ergebnisse von Funktionsaufrufen zwischengespeichert werden und diese zwischengespeicherten Ergebnisse zurückgegeben werden, wenn sie erneut benötigt werden.
Wir werden Folgendes behandeln:
In diesem Artikel wird davon ausgegangen, dass Sie über grundlegende Kenntnisse der Klassen- und Funktionskomponenten in React verfügen.
Wenn Sie sich mit diesen Themen befassen möchten, können Sie sich die offiziellen Komponenten und Requisiten der React-Dokumentation ansehen
: https://reactjs.org/docs/components-and-props.html
Bevor wir die Details der Memoisierung in React besprechen, werfen wir zunächst einen Blick darauf, wie React virtuelles DOM zum Rendern der Benutzeroberfläche verwendet.
Ein reguläres DOM enthält grundsätzlich eine Reihe von Knoten, die in Form eines Baums gehalten werden. Jeder Knoten im DOM stellt ein UI-Element dar. Immer wenn in der Anwendung eine Statusänderung auftritt, werden die entsprechenden Knoten für dieses UI-Element und alle seine untergeordneten Elemente im DOM-Baum aktualisiert, was dann eine Neuzeichnung der UI auslöst.
Mit Hilfe effizienter DOM-Baum-Algorithmen ist das Aktualisieren von Knoten schneller, das Neuzeichnen ist jedoch langsam und kann sich auf die Leistung auswirken, wenn das DOM über eine große Anzahl von UI-Elementen verfügt. Daher wurde in React das virtuelle DOM eingeführt.
Dies ist eine virtuelle Darstellung des realen DOM. Wenn sich nun der Status der Anwendung ändert, aktualisiert React nicht direkt das reale DOM, sondern erstellt ein neues virtuelles DOM. React vergleicht dann dieses neue virtuelle DOM mit dem zuvor erstellten virtuellen DOM, findet die Unterschiede (Anmerkung des Übersetzers: das heißt, findet die Knoten, die aktualisiert werden müssen) und zeichnet dann neu.
Basierend auf diesen Unterschieden kann das virtuelle DOM das reale DOM effizienter aktualisieren. Dies verbessert die Leistung, da das virtuelle DOM nicht einfach das UI-Element und alle seine untergeordneten Elemente aktualisiert, sondern effektiv nur die notwendigen und minimalen Änderungen im realen DOM aktualisiert.
Im vorherigen Abschnitt haben wir gesehen, wie React ein virtuelles DOM verwendet, um DOM-Aktualisierungsvorgänge effizient durchzuführen und so die Leistung zu verbessern. In diesem Abschnitt stellen wir ein Beispiel vor, das die Notwendigkeit der Verwendung von Memoization zur weiteren Verbesserung der Leistung erläutert.
Wir erstellen eine übergeordnete Klasse, die eine Schaltfläche enthält, die eine Variable namens count
erhöht. Die übergeordnete Komponente ruft auch die untergeordnete Komponente auf und übergibt ihr Parameter. Wir haben auch console.log()
-Anweisung in der render
-Methode hinzugefügt:
//Parent.js Die übergeordnete Klasse erweitert React.Component { Konstruktor(Requisiten) { super(Requisiten); this.state = { count: 0 }; } handleClick = () => { this.setState((prevState) => { return { count: prevState.count + 1 }; }); }; render() { console.log("Parent render"); zurückkehren ( <div className="App"> <button onClick={this.handleClick}>Inkrementieren</button> <h2>{this.state.count}</h2> <Child name={"joe"} /> </div> ); } } export default Parent;
Der vollständige Code für dieses Beispiel kann auf CodeSandbox angezeigt werden.
Wir erstellen eine Child
Klasse, die von der übergeordneten Komponente übergebene Parameter akzeptiert und sie in der Benutzeroberfläche anzeigt:
//Child.js Klasse Child erweitert React.Component { render() { console.log("Untergeordnetes Rendern"); zurückkehren ( <div> <h2>{this.props.name}</h2> </div> ); } } export default Child;
count
ändert sich jedes Mal, wenn wir auf die Schaltfläche in der übergeordneten Komponente klicken. Da sich der Status geändert hat, wird die render
der übergeordneten Komponente ausgeführt.
Die an die untergeordnete Komponente übergebenen Parameter ändern sich nicht jedes Mal, wenn die übergeordnete Komponente erneut gerendert wird, daher sollte die untergeordnete Komponente nicht erneut gerendert werden. Wenn wir jedoch den obigen Code ausführen und count
weiter erhöhen, erhalten wir die folgende Ausgabe:
Parent render Untergeordnetes Rendering Übergeordnetes Rendering Untergeordnetes Rendering Übergeordnetes Rendering Untergeordnetes Rendern
Sie können das obige Beispiel in dieser Sandbox ausprobieren und die Konsolenausgabe ansehen.
Anhand der Ausgabe können wir erkennen, dass beim erneuten Rendern der übergeordneten Komponente auch die untergeordnete Komponente erneut gerendert wird, selbst wenn die an die untergeordnete Komponente übergebenen Parameter unverändert bleiben. Dies führt dazu, dass das virtuelle DOM der untergeordneten Komponente eine Vergleichsprüfung mit dem vorherigen virtuellen DOM durchführt. Da es keine Änderungen an unseren untergeordneten Komponenten gibt und alle Requisiten beim erneuten Rendern unverändert bleiben, wird das echte DOM nicht aktualisiert.
Es ist definitiv ein Leistungsvorteil, dass das reale DOM nicht unnötig aktualisiert wird, aber wir können sehen, dass ein neues virtuelles DOM erstellt und eine Diff-Prüfung durchgeführt wird, auch wenn es keine tatsächlichen Änderungen an den untergeordneten Komponenten gibt. Bei kleinen React-Komponenten sind diese Leistungseinbußen vernachlässigbar, bei großen Komponenten können die Auswirkungen auf die Leistung jedoch erheblich sein. Um dieses erneute Rendern und differenzielle Überprüfen des virtuellen DOM zu vermeiden, verwenden wir Memoization.
Im Kontext von React-Anwendungen ist Memoisierung ein Mittel, mit dem die untergeordnete Komponente bei jedem erneuten Rendern der übergeordneten Komponente nur dann erneut gerendert wird, wenn sich die Requisiten ändern, von denen sie abhängt. Wenn es keine Änderungen an den Requisiten gibt, von denen die untergeordnete Komponente abhängt, führt sie die Render-Methode nicht aus und gibt die zwischengespeicherten Ergebnisse zurück. Da die Render-Methode nicht ausgeführt wird, erfolgt keine virtuelle DOM-Erstellung und Differenzprüfung, was zu einer verbesserten Leistung führt.
Sehen wir uns nun an, wie man Memoization in Klassen- und Funktionskomponenten implementiert, um dieses unnötige erneute Rendern zu vermeiden.
Um Memoization in einer Klassenkomponente zu implementieren, verwenden wir React.PureComponent. React.PureComponent
implementiert ShouldComponentUpdate(), das einen oberflächlichen Vergleich state
und props
durchführt und die React-Komponente nur dann neu rendert, wenn sich Requisiten oder Status ändern.
Ändern Sie die untergeordnete Komponente in einen Code wie diesen:
//Child.js class Child erweitert React.PureComponent { // Hier ändern wir React.Component in React.PureComponent render() { console.log("Untergeordnetes Rendern"); zurückkehren ( <div> <h2>{this.props.name}</h2> </div> ); } } export default Child;
Der vollständige Code für dieses Beispiel wird in dieser Sandbox angezeigt.
Die übergeordnete Komponente bleibt unverändert. Wenn wir nun count
in der übergeordneten Komponente erhöhen, sieht die Ausgabe in der Konsole folgendermaßen aus:
Übergeordnetes Rendern Untergeordnetes Rendering Übergeordnetes Rendering Übergeordnetes Rendern
Beim ersten Rendern wird die render
sowohl der übergeordneten Komponente als auch der untergeordneten Komponente aufgerufen.
Bei jedem erneuten Rendern nach Erhöhung count
wird nur die render
der übergeordneten Komponente aufgerufen. Untergeordnete Komponenten werden nicht erneut gerendert.
Um die Memoisierung in Funktionskomponenten zu implementieren, verwenden wir React.memo(). React.memo()
ist eine Komponente höherer Ordnung (HOC), die ähnliche Aufgaben wie PureComponent
ausführt, um unnötiges erneutes Rendern zu vermeiden.
Hier ist der Code für die Funktionskomponente:
//Child.js Exportfunktion Child(props) { console.log("Untergeordnetes Rendern"); zurückkehren ( <div> <h2>{props.name}</h2> </div> ); } export default React.memo(Child); // Hier fügen wir HOC zur untergeordneten Komponente hinzu, um Memoization zu implementieren
und konvertieren auch die übergeordnete Komponente in eine Funktionskomponente, wie unten gezeigt:
//Parent.js Standardfunktion exportieren Parent() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; console.log("Parent render"); zurückkehren ( <div> <button onClick={handleClick}>Inkrementieren</button> <h2>{count}</h2> <Child name={"joe"} /> </div> ); }
Der vollständige Code für dieses Beispiel ist in dieser Sandbox zu sehen.
Wenn wir nun count
in der übergeordneten Komponente erhöhen, wird Folgendes an die Konsole ausgegeben:
Parent render Untergeordnetes Rendering Übergeordnetes Rendering Übergeordnetes Rendering
dem übergeordneten Rendern vonReact.memo()
Im obigen Beispiel sehen wir, dass, wenn wir React.memo()
HOC für eine untergeordnete Komponente verwenden, die untergeordnete Komponente nicht erneut gerendert wird, obwohl die übergeordnete Komponente erneut gerendert wird.
Eine Kleinigkeit ist jedoch zu beachten: Wenn wir eine Funktion als Parameter an die untergeordnete Komponente übergeben, wird die untergeordnete Komponente auch nach der Verwendung von React.memo()
erneut gerendert. Schauen wir uns dazu ein Beispiel an.
Wir werden die übergeordnete Komponente wie unten gezeigt ändern. Hier fügen wir eine Handlerfunktion hinzu und übergeben sie als Parameter an die untergeordnete Komponente:
//Parent.js Standardfunktion exportieren Parent() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; const handler = () => { console.log("handler"); // Die Handlerfunktion wird hier an die untergeordnete Komponente übergeben}; console.log("Parent render"); zurückkehren ( <div className="App"> <button onClick={handleClick}>Inkrementieren</button> <h2>{count}</h2> <Child name={"joe"} childFunc={handler} /> </div> ); }
Der Code der untergeordneten Komponente bleibt unverändert. Wir werden keine von übergeordneten Komponenten übergebenen Funktionen in untergeordneten Komponenten verwenden:
//Child.js Exportfunktion Child(props) { console.log("Untergeordnetes Rendern"); zurückkehren ( <div> <h2>{props.name}</h2> </div> ); } export default React.memo(Child);
Wenn wir nun count
in der übergeordneten Komponente erhöhen, wird die untergeordnete Komponente gleichzeitig neu gerendert, obwohl sich die übergebenen Parameter nicht ändern.
Was führt also dazu, dass die Unterkomponente erneut gerendert wird? Die Antwort ist, dass jedes Mal, wenn die übergeordnete Komponente erneut gerendert wird, eine neue handler
erstellt und an die untergeordnete Komponente übergeben wird. Da die handle
-Funktion nun bei jedem erneuten Rendern neu erstellt wird, stellt die untergeordnete Komponente bei einem oberflächlichen Vergleich der Requisiten fest, dass sich handler
Referenz geändert hat, und rendert die untergeordnete Komponente erneut.
Als Nächstes besprechen wir, wie Sie dieses Problem beheben können.
useCallback()
um weitere erneute Renderings zu vermeiden.Das Hauptproblem beim erneuten Rendern untergeordneter Komponenten besteht darin, dass die handler
neu erstellt wird, wodurch sich der an die untergeordnete Komponente übergebene Verweis ändert. Deshalb brauchen wir eine Möglichkeit, diese Doppelarbeit zu vermeiden. Wenn die handler
-Funktion nicht neu erstellt wird, ändert sich der Verweis auf die handler
-Funktion nicht, sodass die untergeordnete Komponente nicht erneut gerendert wird.
Um zu vermeiden, dass die Funktion jedes Mal neu erstellt werden muss, wenn die übergeordnete Komponente gerendert wird, verwenden wir einen React Hook namens useCallback(). Hooks wurden in React 16 eingeführt. Um mehr über Hooks zu erfahren, können Sie sich die offizielle Hooks-Dokumentation von React ansehen oder sich „React Hooks: How to Get Started & Build Your Own“ ansehen.
Der useCallback()
Hook akzeptiert zwei Parameter: eine Callback-Funktion und eine Liste von Abhängigkeiten .
Das Folgende ist ein Beispiel für useCallback()
:
const handleClick = useCallback(() => { //Tu etwas }, [x,y]);
Hier wird useCallback()
zur Funktion handleClick()
hinzugefügt. Der zweite Parameter [x, y]
kann ein leeres Array, eine einzelne Abhängigkeit oder eine Liste von Abhängigkeiten sein. Die Funktion handleClick()
wird nur dann neu erstellt, wenn sich eine der im zweiten Parameter genannten Abhängigkeiten ändert.
Wenn sich die in useCallback()
genannten Abhängigkeiten nicht geändert haben, wird die als erstes Argument erwähnte Memoized-Version der Callback-Funktion zurückgegeben. Wir werden die übergeordnete Komponente so ändern, dass sie useCallback()
Hook für Handler verwendet, die an die untergeordnete Komponente übergeben werden:
//Parent.js Standardfunktion exportieren Parent() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; const handler = useCallback(() => { // UseCallback() für die Handler-Funktion verwenden console.log("handler"); }, []); console.log("Parent render"); zurückkehren ( <div className="App"> <button onClick={handleClick}>Inkrementieren</button> <h2>{count}</h2> <Child name={"joe"} childFunc={handler} /> </div> ); }
Der Code der untergeordneten Komponente bleibt unverändert.
Der vollständige Code für dieses Beispiel befindet sich in dieser Sandbox.
Wenn wir count
in der übergeordneten Komponente des obigen Codes erhöhen, sehen wir die folgende Ausgabe:
Parent render Untergeordnetes Rendering Übergeordnetes Rendering Übergeordnetes Rendering Übergeordnetes Rendern
Da wir useCallback()
Hook für handler
in der übergeordneten Komponente verwenden, wird die handler
-Funktion nicht jedes Mal neu erstellt, wenn die übergeordnete Komponente erneut gerendert wird, und die Memoization-Version handler
wird an die untergeordnete Komponente übergeben. Die untergeordnete Komponente führt einen oberflächlichen Vergleich durch und stellt fest, dass sich der Verweis auf die handler
nicht geändert hat, sodass sie die render
-Methode nicht aufruft.
die Memoisierung ein gutes Mittel ist, um unnötiges erneutes Rendern von Komponenten zu vermeiden, wenn sich ihr Status oder ihre Requisiten nicht geändert haben, und dadurch die Leistung von React-Anwendungen zu verbessern. Sie könnten erwägen, Memoization zu allen Ihren Komponenten hinzuzufügen, aber das ist nicht unbedingt die Möglichkeit, leistungsstarke React-Komponenten zu erstellen. Die Memoisierung sollte nur verwendet werden, wenn die Komponente:
In diesem Tutorial haben wir Folgendes verstanden:
React.memo()
für Funktionskomponenten und React.PureComponent
für Klassenkomponenten.React.memo()
zurückgesetzt wird.useCallback()
Probleme beim erneuten Rendern zu vermeiden, wenn Funktionen als Requisiten an untergeordnete Komponenten übergeben werden.Ich hoffe, dass Ihnen diese Einführung in React Memoization hilfreich sein wird!
Ursprüngliche Adresse: https://www.sitepoint.com/implement-memoization-in-react-to-improve-performance/ Ursprünglicher
Autor: Nida Khan