Verbessern der Funktionalität von Reaktionskomponenten mit React.memo ()

Wir präsentieren Ihnen eine Übersetzung des Artikels von Chidume Nnamdi, der auf blog.bitsrc.io veröffentlicht wurde. Wenn Sie lernen möchten, wie Sie unnötiges Rendern vermeiden und wie neue Tools in React nützlich sind, sind Sie bei cat willkommen.



Das React.js-Team arbeitet hart daran, dass React so schnell wie möglich ausgeführt wird. Damit Entwickler ihre React-Anwendungen beschleunigen können, wurden die folgenden Tools hinzugefügt:

  • React.lazy und Suspense für verzögertes Laden von Komponenten;
  • Reine Komponente
  • Lifecycle-Hooks solltenComponentUpdate (...) {...}.

In diesem Artikel werden wir unter anderem ein weiteres Optimierungstool betrachten, das in React v16.6 hinzugefügt wurde, um Komponentenfunktionen zu beschleunigen - React.memo .

Tipp: Verwenden Sie Bit , um React-Komponenten zu installieren und freizugeben. Verwenden Sie Ihre Komponenten, um neue Anwendungen zu erstellen und diese mit dem Team zu teilen, um die Arbeit zu beschleunigen. Probieren Sie es aus!



Zusätzliches Rendern


In React entspricht jede Komponente einer Ansichtseinheit. Komponenten haben auch Zustände. Wenn sich der Statuswert aufgrund von Benutzeraktionen ändert, erkennt die Komponente, dass ein erneutes Zeichnen erforderlich ist. Die React-Komponente kann beliebig oft neu gezeichnet werden. In einigen Fällen ist dies erforderlich, aber meistens können Sie auf einen Renderer verzichten, zumal dies die Anwendung erheblich verlangsamt.

Betrachten Sie die folgende Komponente:

import React from 'react'; class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } render() { return ( <div > {this.state.count} <button onClick={()=>this.setState({count: 1})}>Click Me</button> </div> ); } } export default TestC; 

Der Anfangswert des Status {count: 0} ist 0. Wenn Sie auf die Schaltfläche Click me klicken, wird der Count-Status zu 1. Auf unserem Bildschirm ändert sich 0 ebenfalls zu 1. Wenn wir jedoch erneut auf die Schaltfläche klicken, beginnen Probleme: Die Komponente sollte nicht neu gezeichnet werden, da dies der Fall ist Der Zustand hat sich nicht geändert. Der Zählerwert "to" ist 1, der neue Wert ist auch eins, was bedeutet, dass das DOM nicht aktualisiert werden muss.

Um das Update unseres TestC zu sehen, bei dem derselbe Status zweimal festgelegt wird, habe ich zwei Lebenszyklusmethoden hinzugefügt. React startet den componentWillUpdate-Zyklus, wenn die Komponente aufgrund einer Statusänderung aktualisiert / neu gezeichnet wird. Der Reaktionszyklus componentdidUpdate beginnt, wenn eine Komponente erfolgreich gerendert wurde.

Wenn wir die Komponente im Browser starten und mehrmals versuchen, auf die Schaltfläche "Klick mich" zu klicken, erhalten wir das folgende Ergebnis:



Das Wiederholen des Eintrags componentWillUpdate in unserer Konsole zeigt an, dass die Komponente auch dann neu gezeichnet wird, wenn sich der Status nicht ändert. Dies ist ein zusätzlicher Render.

Pure Component / shouldComponentUpdate


Mit dem Lifecycle-Hook shouldComponentUpdate wird unnötiges Rendern in React-Komponenten vermieden.

React startet die shouldComponentUpdate- Methode zu Beginn des Komponenten-Renderings und erhält grünes Licht von dieser Methode, um den Prozess fortzusetzen, oder ein Signal, dass der Prozess gesperrt ist .

Lassen Sie unser shouldComponentUpdate so aussehen:

 shouldComponentUpdate(nextProps, nextState) { return true } 

  • nextProps : Der nächste props , den die Komponente erhält.
  • nextState : Der nächste nextState , den die Komponente erhält.

Daher erlauben wir React, die Komponente zu rendern, da der Rückgabewert true .

Angenommen, wir schreiben Folgendes:

 shouldComponentUpdate(nextProps, nextState) { return false } 

In diesem Fall verbieten wir React, die Komponente zu rendern, da false zurückgegeben wird.
Aus dem Obigen folgt, dass wir zum Rendern der Komponente true . Jetzt können wir die TestC-Komponente wie folgt umschreiben:

 import React from 'react'; class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true } render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div> ); } } export default TestC; 

Wir haben der TestC-Komponente einen shouldComponentUpdate-Hook hinzugefügt. Jetzt wird der count im aktuellen this.state.count mit dem count im nächsten nextState.count this.state.count verglichen. Wenn sie gleich sind === , wird nicht neu === und false zurückgegeben. Wenn sie nicht gleich sind, wird true zurückgegeben und ein Renderer gestartet, um den neuen Wert anzuzeigen.

Wenn wir den Code in einem Browser testen, sehen wir ein bekanntes Ergebnis:



Wenn Click Me mehrmals auf die Schaltfläche "Klicken" Click Me , sehen wir nur Folgendes (nur einmal angezeigt!):

componentWillUpdate
componentDidUpdate




Sie können den Status der TestC-Komponente auf der Registerkarte React DevTools ändern. Klicken Sie auf die Registerkarte Reagieren, wählen Sie rechts TestC aus, und Sie sehen den Zählerstatuswert:



Dieser Wert kann geändert werden. Klicken Sie auf den Zählertext, geben Sie 2 ein und drücken Sie die Eingabetaste.



Der Zählstatus ändert sich und in der Konsole sehen wir:

 componentWillUpdate componentDidUpdate componentWillUpdate componentDidUpdate 



Der vorherige Wert war 1 und der neue Wert war 2, daher war ein erneutes Zeichnen erforderlich.
Fahren wir mit der reinen Komponente fort .

Pure Component wurde in React in Version v15.5 angezeigt. Es wird verwendet, um Standardwerte zu vergleichen ( change detection ). Mit der extend React.PureComponent Sie Komponenten nicht die Lebenszyklusmethode " shouldComponentUpdate hinzufügen: Die Änderungsverfolgung erfolgt von selbst.

Fügen Sie der TestC-Komponente eine PureComponent hinzu.

 import React from 'react'; class TestC extends React.PureComponent { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } /*shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true }*/ render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div > ); } } export default TestC; 

Wie Sie sehen können, shouldComponentUpdate wir shouldComponentUpdate in einen Kommentar. Wir brauchen es nicht mehr: Die ganze Arbeit erledigt React.PureComponent .

Wenn Sie den Browser neu starten, um die neue Lösung zu testen, und mehrmals auf die Schaltfläche "Klicken" Click Me Folgendes:





Wie Sie sehen können, wurde nur eine component*Update Eintrag in der Konsole angezeigt.

Nachdem wir gesehen haben, wie Sie in React mit dem Neuzeichnen in den Komponentenklassen von ES6 arbeiten, fahren wir mit den Komponentenfunktionen fort. Wie kann man mit ihnen die gleichen Ergebnisse erzielen?

Funktionskomponenten


Wir wissen bereits, wie die Arbeit mit Klassen mithilfe der Lebenszyklusmethode Pure Component und shouldComponentUpdate optimiert shouldComponentUpdate . Niemand argumentiert, dass Klassenkomponenten die Hauptkomponenten von React sind, aber Sie können Funktionen als Komponenten verwenden.

 function TestC(props) { return ( <div> I am a functional component </div> ) } 

Es ist wichtig, sich daran zu erinnern, dass Funktionskomponenten im Gegensatz zu Klassenkomponenten keinen Status haben (obwohl dies jetzt, da useState Hooks useState sind, argumentiert werden kann), was bedeutet, dass wir ihre Neuzeichnung nicht konfigurieren können. Die Lebenszyklusmethoden, die wir bei der Arbeit mit Klassen verwendet haben, stehen uns hier nicht zur Verfügung. Wenn wir Funktionskomponenten Hooks für den Lebenszyklus hinzufügen können, können wir die Methode shouldComponentUpdate hinzufügen, um React mitzuteilen, dass ein Funktionsrenderer benötigt wird. (Vielleicht hat der Autor im letzten Satz einen sachlichen Fehler gemacht. - Ungefähr Ed.) Und natürlich können wir die extend React.PureComponent nicht verwenden.

Wir verwandeln unsere Komponentenklasse ES6 TestC in eine Komponentenfunktion.

 import React from 'react'; const TestC = (props) => { console.log(`Rendering TestC :` props) return ( <div> {props.count} </div> ) } export default TestC; // App.js <TestC count={5} /> 

Nach dem Rendern in der Konsole wird der Eintrag Rendering TestC :5 .



Öffnen Sie DevTools und klicken Sie auf die Registerkarte Reagieren. Hier werden wir versuchen, den Wert der Eigenschaften der TestC-Komponente zu ändern. Wählen Sie TestC aus, und die Zählereigenschaften mit allen Eigenschaften und Werten von TestC werden rechts geöffnet. Wir sehen nur den Zähler mit dem aktuellen Wert 5.

Klicken Sie auf die Nummer 5, um den Wert zu ändern. Stattdessen wird ein Eingabefenster angezeigt.



Wenn wir den numerischen Wert ändern und die Eingabetaste drücken, ändern sich die Eigenschaften der Komponente entsprechend dem eingegebenen Wert. Angenommen, bei 45.



Wechseln Sie zur Registerkarte Konsole.



Die TestC-Komponente wurde neu gezeichnet, da der vorherige Wert von 5 auf den aktuellen Wert von 45 geändert wurde. Gehen Sie zurück zur Registerkarte Reagieren, ändern Sie den Wert auf 45 und kehren Sie dann zur Konsole zurück.



Wie Sie sehen, wird die Komponente erneut gezeichnet, obwohl der vorherige und der neue Wert identisch sind. :(

Wie verwalte ich einen Renderer?

Lösung: React.memo ()


React.memo() ist eine neue Funktion, die in React v16.6 eingeführt wurde. Das Funktionsprinzip ähnelt dem Prinzip von React.PureComponent : Hilfe beim Verwalten des Neuzeichnens von Komponentenfunktionen. React.memo(...) für Klassenkomponenten ist React.PureComponent für Funktionskomponenten.

Wie arbeite ich mit React.memo (...)?
Ziemlich einfach. Angenommen, wir haben eine Komponentenfunktion.

 const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> ) } 

Wir müssen FuncComponent nur als Argument an die Funktion React.memo übergeben.

 const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> ) } const MemodFuncComponent = React.memo(FunComponent) 

React.memo gibt purified MemodFuncComponent . Dies werden wir im JSX-Markup zeichnen. Wenn sich die Eigenschaften und der Status einer Komponente ändern, vergleicht React die vorherigen und aktuellen Eigenschaften und Zustände der Komponente. Und nur wenn sie nicht identisch sind, wird die Komponentenfunktion neu gezeichnet.

Wenden Sie dies auf die TestC-Funktionskomponente an.

 let TestC = (props) => { console.log('Rendering TestC :', props) return ( <div> { props.count } </> ) } TestC = React.memo(TestC); 

Öffnen Sie einen Browser und laden Sie die Anwendung herunter. Öffnen Sie DevTools und wechseln Sie zur Registerkarte Reagieren. Wählen Sie <Memo(TestC)> .

Wenn wir im Block rechts die Eigenschaften des Zählers auf 89 ändern, wird die Anwendung neu gezeichnet.



Wenn wir den Wert auf den vorherigen Wert ändern, 89, dann ...



Es wird kein Neuzeichnen geben!

Ehre sei React.memo (...)! :) :)

Ohne React.memo(...) in unserem ersten Beispiel wird die TestC-Komponentenfunktion neu gezeichnet, selbst wenn der vorherige Wert auf den identischen Wert geändert wird. Dank React.memo(...) können wir jetzt unnötiges Rendern von Komponentenfunktionen vermeiden.

Fazit


  • Lassen Sie uns die Liste durchgehen?
  • React.PureComponent - Silber;
  • React.memo(...) - Gold;
  • React.PureComponent arbeitet mit ES6-Klassen.
  • React.memo(...) arbeitet mit Funktionen;
  • React.PureComponent optimiert das Neuzeichnen von ES6-Klassen.
  • React.memo(...) optimiert das Neuzeichnen von Funktionen.
  • Feature-Optimierung ist eine großartige Idee;
  • React wird nie wieder dieselbe sein.

Wenn Sie Fragen zum Artikel oder zusätzliche Informationen, Korrekturen oder Einwände haben, zögern Sie nicht, mir Kommentare, E-Mails oder private Nachrichten zu schreiben.

Vielen Dank!

Source: https://habr.com/ru/post/de442116/


All Articles