Kam zu wissen, dass ab React v15.3.0 eine neue Basisklasse namens PureComponent mit PureRenderMixin integriert ist. Ich verstehe, dass unter der Haube ein flacher Vergleich der Requisiten in shouldComponentUpdate
durchgeführt wird.
Jetzt haben wir 3 Möglichkeiten, eine React-Komponente zu definieren:
PureComponent
erweitertComponent
erweitertVor einiger Zeit haben wir zustandslose Komponenten als reine Komponenten oder sogar als dumme Komponenten bezeichnet. Scheint, als hätte sich die gesamte Definition des Wortes "rein" in React geändert.
Obwohl ich grundlegende Unterschiede zwischen diesen drei verstehe, bin ich mir immer noch nicht sicher, wann ich was wählen soll . Was sind auch die Auswirkungen auf die Leistung und die jeweiligen Kompromisse?
Dies sind die Fragen, von denen ich eine Klärung erwarte:
PureComponent
erweitern (aus Gründen der Leistung)?Component
erweitern müssen, wenn ich PureComponent
immer verwenden kann, um die Leistung zu verbessern?Das Erweitern von React.PureComponent
oder von React.Component
mit einer benutzerdefinierten shouldComponentUpdate
-Methode hat Auswirkungen auf die Leistung. Die Verwendung zustandsloser Funktionskomponenten ist eine "architektonische" Wahl und bietet (noch) keine Leistungsvorteile.
Für einfache Darstellungskomponenten, die einfach wiederverwendet werden müssen, ziehen Sie zustandslose Funktionskomponenten vor. Auf diese Weise sind Sie sicher, dass sie von der eigentlichen App-Logik entkoppelt sind, dass sie einfach zu testen sind und keine unerwarteten Nebenwirkungen haben. Die Ausnahme ist, wenn Sie aus irgendeinem Grund eine Menge von ihnen haben oder wenn Sie wirklich ihre Render-Methode optimieren müssen (da Sie shouldComponentUpdate
nicht für eine zustandslose Funktionskomponente definieren können).
Erweitern Sie PureComponent
, wenn Sie wissen, dass Ihre Ausgabe von einfachen Requisiten/Zuständen abhängt ("simple" bedeutet keine verschachtelten Datenstrukturen, da PureComponent einen flachen Vergleich durchführt) UND Sie benötigen einige Leistungsverbesserungen.
Erweitern Sie Component
und implementieren Sie Ihr eigenes shouldComponentUpdate
, wenn Sie einige Leistungssteigerungen benötigen, indem Sie eine benutzerdefinierte Vergleichslogik zwischen nächsten/aktuellen Requisiten und dem Status ausführen. Beispielsweise können Sie schnell einen tiefen Vergleich mit lodash # isEqual durchführen:
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
Auch das Implementieren von shouldComponentUpdate
oder das Erweitern von PureComponent
sind Optimierungen. Wie üblich sollten Sie dies nur dann prüfen, wenn Sie Leistungsprobleme haben ( vermeiden Sie vorzeitige Optimierungen ). Als Faustregel versuche ich immer, diese Optimierungen vorzunehmen, nachdem sich die Anwendung im Arbeitszustand befindet und die meisten Funktionen bereits implementiert sind. Es ist viel einfacher, sich auf Leistungsprobleme zu konzentrieren, wenn sie tatsächlich in die Quere kommen.
Funktionslose zustandslose Komponenten:
Diese werden nur über eine Funktion definiert. Da es für eine zustandslose Komponente keinen internen Status gibt, hängt die Ausgabe (was gerendert wird) nur von den Requisiten ab, die als Eingabe für diese Funktion angegeben werden.
Pros:
Einfachste Möglichkeit, eine Komponente in React zu definieren. Wenn Sie keinen Zustand verwalten müssen, warum sollten Sie sich mit Klassen und Vererbung beschäftigen? Einer der Hauptunterschiede zwischen einer Funktion und einer Klasse besteht darin, dass Sie mit der Funktion sicher sind, dass die Ausgabe nur von der Eingabe abhängt (nicht von der Historie der vorherigen Ausführungen).
Idealerweise sollten Sie in Ihrer App möglichst viele zustandslose Komponenten verwenden, da dies normalerweise bedeutet, dass Sie Ihre Logik außerhalb der Ansichtsebene verschoben haben und sie in eine Art "redux" verschoben haben. Dies bedeutet, dass Sie Ihre reale Logik testen können, ohne etwas zu rendern (viel einfacher zu testen, wiederverwendbar usw.).
Nachteile:
Keine Lebenszyklusmethoden. Sie haben keine Möglichkeit, componentDidMount
und andere Freunde zu definieren. Normalerweise tun Sie dies in einer übergeordneten Komponente, die höher in der Hierarchie ist, sodass Sie alle untergeordneten Elemente in zustandslose Elemente konvertieren können.
Es gibt keine Möglichkeit, manuell zu steuern, wann ein erneutes Rendern erforderlich ist, da Sie shouldComponentUpdate
nicht definieren können. Ein erneutes Rendern erfolgt jedes Mal, wenn die Komponente neue Requisiten erhält (keine Möglichkeit zum Vergleich von flachen Ebenen usw.). In Zukunft könnte React automatisch statuslose Komponenten optimieren. Derzeit können einige Bibliotheken verwendet werden. Da zustandslose Komponenten nur Funktionen sind, handelt es sich im Grunde um das klassische Problem der "Funktionserinnerung".
Refs werden nicht unterstützt: https://github.com/facebook/react/issues/4936
Eine Komponente, die die PureComponent-Klasse erweitert VS Eine normale Komponente, die die Component-Klasse erweitert:
React verwendet, um eine PureRenderMixin
zu haben, die Sie an eine Klasse anhängen können, die mit React.createClass
-Syntax definiert ist. Das Mixin würde einfach ein shouldComponentUpdate
definieren, das einen flachen Vergleich zwischen den nächsten Stützen und dem nächsten Zustand durchführt, um zu überprüfen, ob sich dort etwas geändert hat. Wenn sich nichts ändert, ist keine erneute Wiedergabe erforderlich.
Wenn Sie die ES6-Syntax verwenden möchten, können Sie keine Mixins verwenden. Zur Vereinfachung hat React eine PureComponent
-Klasse eingeführt, von der Sie erben können, anstatt Component
zu verwenden. PureComponent
implementiert shouldComponentUpdate
genauso wie PureRendererMixin
. Es ist meistens eine bequeme Sache, so dass Sie es nicht selbst implementieren müssen, da ein flacher Vergleich zwischen aktuellem/nächstem Status und Requisiten wahrscheinlich das häufigste Szenario ist, das Ihnen schnelle Leistungsgewinne bescheren kann.
Beispiel:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
Wie Sie sehen, hängt die Ausgabe von props.imageUrl
und props.username
ab. Wenn Sie in einer übergeordneten Komponente <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />
mit denselben Requisiten rendern, ruft React jedes Mal render
auf, auch wenn die Ausgabe genau gleich wäre. Denken Sie daran, dass React dom diffing implementiert, damit das DOM nicht aktualisiert wird. Das Dom-Diffing durchzuführen, kann jedoch teuer sein, daher wäre es in diesem Szenario eine Verschwendung.
Wenn die UserAvatar
-Komponente stattdessen PureComponent
erweitert, wird ein flacher Vergleich durchgeführt. Und weil Requisiten und nextProps gleich sind, wird render
überhaupt nicht aufgerufen.Hinweise zur Definition von "rein" in React:.
Im Allgemeinen ist eine "reine Funktion" eine Funktion, die bei gleicher Eingabe immer das gleiche Ergebnis auswertet. Die Ausgabe (für React ist das, was von der render
-Methode zurückgegeben wird) hängt nicht von der Historie/dem Status ab und hat keine Nebenwirkungen (Operationen, die die "Welt" außerhalb der Funktion verändern).
In React sind zustandslose Komponenten gemäß der obigen Definition nicht unbedingt reine Komponenten, wenn Sie "stateless" eine Komponente aufrufen, die niemals this.setState
aufruft und keine this.state
verwendet.
Tatsächlich können Sie in einem PureComponent
während der Lebenszyklusmethoden noch Nebenwirkungen haben. Sie können zum Beispiel eine Ajax-Anforderung in componentDidMount
senden oder eine DOM-Berechnung durchführen, um die Höhe eines Divs in render
dynamisch anzupassen.
Die Definition von "dummen Komponenten" hat eine "praktischere" Bedeutung (zumindest in meinem Verständnis): Eine dumme Komponente "wird" über Requisiten von einer übergeordneten Komponente informiert und weiß nicht, wie sie vorgeht, sondern verwendet Requisiten stattdessen Rückrufe.
Beispiel eines "intelligenten" AvatarComponent
:
class AvatarComponent extends Component {
expandAvatar () {
this.setState({ loading: true });
sendAjaxRequest(...).then(() => {
this.setState({ loading: false });
});
}
render () {
<div onClick={this.expandAvatar}>
<img src={this.props.username} />
</div>
}
}
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
In the end I would say that "dumb", "stateless" and "pure" are quite different concepts that can sometimes overlap, but not necessarily, depending mostly on your use case.
ich bin kein Genie der Reaktion, aber aus meinem Verständnis können wir jede Komponente in folgenden Situationen verwenden
Zustandslose Komponente - Dies ist die Komponente, die keinen Lebenszyklus hat. Daher sollten diese Komponenten beim Wiederholen des Wiederholungselements der übergeordneten Komponente verwendet werden, z. B. beim Rendern der Textliste, die nur die Informationen anzeigt und keine enthält auszuführende Aktionen.
Reine Komponente - Dies sind die Elemente, die einen Lebenszyklus haben, und sie geben immer das gleiche Ergebnis zurück, wenn ein bestimmter Satz von Requisiten gegeben wird. Diese Komponenten können verwendet werden, wenn eine Ergebnisliste oder bestimmte Objektdaten angezeigt werden, die keine komplexen untergeordneten Elemente enthalten und zum Ausführen von Vorgängen verwendet werden, die nur sich selbst betreffen. Eine solche Liste der Benutzerkarten oder der Liste der Produktkarten (grundlegende Produktinformationen) und die einzige Aktion, die ein Benutzer ausführen kann, ist das Klicken, um die Detailseite anzuzeigen oder in den Warenkorb zu legen.
Normale Komponenten oder komplexe Komponenten - Ich habe Begriff komplexe Komponente verwendet, da es sich hierbei normalerweise um Komponenten auf Seitenebene handelt und viele untergeordnete Komponenten enthalten sind. Jedes Kind kann sich auf seine eigene Art und Weise verhalten, so dass Sie nicht 100% sein können Stellen Sie sicher, dass es bei gegebenem Status dasselbe Ergebnis liefert. Wie gesagt, sollten diese normalerweise als Behälterbestandteile verwendet werden
React.Component
ist die "normale" Standardkomponente. Sie deklarieren sie mit dem Schlüsselwort class
und extends React.Component
. Stellen Sie sich sie als eine Klasse vor, mit Lebenszyklusmethoden, Ereignishandlern und anderen Methoden.
React.PureComponent
ist ein React.Component
, der shouldComponentUpdate()
mit einer Funktion implementiert, die einen flachen Vergleich von props
und state
durchführt. Sie müssen forceUpdate()
verwenden, wenn Sie wissen, dass die Komponente Requisiten oder verschachtelte Daten enthält, die sich geändert haben, und dass Sie erneut rendern möchten. Sie sind daher nicht besonders gut geeignet, wenn Sie Komponenten zum erneuten Rendern benötigen, wenn Arrays oder Objekte als Requisiten übergeben werden oder in Ihrem Status geändert werden.
Funktionskomponenten sind solche, die keine Lebenszyklusfunktionen haben. Sie sind angeblich staatenlos, aber sie sind so nett und sauber, dass wir jetzt Haken haben (seit React 16.8), sodass Sie immer noch einen Zustand haben können. Ich denke, das sind nur "saubere Komponenten".