Wie entscheiden Sie sich, wie wählen Sie zwischen diesen drei basierend auf dem Zweck / der Größe / den Requisiten / dem Verhalten unserer Komponenten?
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 sofort einsatzbereiten Leistungsvorteile.
Für einfache Komponenten nur für Präsentationen, die leicht wiederverwendet werden müssen, bevorzugen Sie zustandslose Funktionskomponenten. Auf diese Weise sind Sie sicher, dass sie von der eigentlichen App-Logik entkoppelt sind, dass sie kinderleicht zu testen sind und keine unerwarteten Nebenwirkungen haben. Die Ausnahme ist, wenn Sie aus irgendeinem Grund viele davon haben oder wenn Sie die Rendermethode wirklich optimieren müssen (da Sie dies shouldComponentUpdate
für eine zustandslose Funktionskomponente nicht definieren können ).
Erweitern PureComponent
Sie, wenn Sie wissen, dass Ihre Ausgabe von einfachen Requisiten / Status abhängt ("einfach" bedeutet, dass keine verschachtelten Datenstrukturen vorhanden sind, da PureComponent einen flachen Vergleich durchführt) UND Sie einige Leistungsverbesserungen benötigen / erhalten können.
Erweitern Component
und implementieren Sie Ihre eigenen, shouldComponentUpdate
wenn Sie Leistungssteigerungen benötigen, indem Sie eine benutzerdefinierte Vergleichslogik zwischen den nächsten / aktuellen Requisiten und dem Status durchführen. Mit lodash # isEqual können Sie beispielsweise schnell einen umfassenden Vergleich durchführen:
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
Wenn Sie Ihre eigenen implementieren shouldComponentUpdate
oder erweitern, handelt PureComponent
es sich auch um 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 die Anwendung in einem funktionierenden Zustand ist, wobei die meisten Funktionen bereits implementiert sind. Es ist viel einfacher, sich auf Leistungsprobleme zu konzentrieren, wenn sie tatsächlich im Weg sind.
Mehr Details
Funktionale zustandslose Komponenten:
Diese werden nur mit einer 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 wurden.
Vorteile:
Einfachste Möglichkeit, eine Komponente in React zu definieren. Wenn Sie keinen Status verwalten müssen, warum sollten Sie sich dann um Klassen und Vererbung kümmern? Einer der Hauptunterschiede zwischen einer Funktion und einer Klasse besteht darin, dass Sie bei 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 darauf abzielen, so viele zustandslose Komponenten wie möglich zu haben, da dies normalerweise bedeutet, dass Sie Ihre Logik außerhalb der Ansichtsebene verschoben und in eine Art Redux verschoben haben. Dies bedeutet, dass Sie Ihre reale Logik testen können, ohne etwas rendern zu müssen (viel einfacher zu testen, wiederverwendbarer usw.).
Nachteile:
Keine Lebenszyklusmethoden. Sie haben keine Möglichkeit, componentDidMount
andere Freunde zu definieren . Normalerweise tun Sie dies innerhalb einer übergeordneten Komponente, die höher in der Hierarchie liegt, damit Sie alle untergeordneten Komponenten in zustandslose verwandeln können.
Keine Möglichkeit, manuell zu steuern, wann ein erneutes Rendern erforderlich ist, da Sie nicht definieren können shouldComponentUpdate
. Ein erneutes Rendern erfolgt jedes Mal, wenn die Komponente neue Requisiten erhält (keine Möglichkeit zum flachen Vergleich usw.). In Zukunft könnte React zustandslose Komponenten automatisch optimieren. Derzeit können Sie einige Bibliotheken verwenden. Da zustandslose Komponenten nur Funktionen sind, ist dies im Grunde das klassische Problem der "Funktionserinnerung".
Referenzen 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:
Reagieren PureRenderMixin
Sie, um eine Klasse anzuhängen, die mithilfe der React.createClass
Syntax definiert wurde . Das Mixin würde einfach shouldComponentUpdate
einen flachen Vergleich zwischen den nächsten Requisiten und dem nächsten Zustand definieren, um zu überprüfen, ob sich dort etwas geändert hat. Wenn sich nichts ändert, muss kein erneutes Rendern durchgeführt werden.
Wenn Sie die ES6-Syntax verwenden möchten, können Sie keine Mixins verwenden. Aus Bequemlichkeitsgründen hat React eine PureComponent
Klasse eingeführt, von der Sie erben können, anstatt sie zu verwenden Component
. PureComponent
implementiert nur shouldComponentUpdate
in der gleichen Weise wie die PureRendererMixin
. Es ist meistens eine bequeme Sache, so dass Sie es nicht selbst implementieren müssen, da ein flacher Vergleich zwischen aktuellem / nächstem Zustand und Requisiten wahrscheinlich das häufigste Szenario ist, das Ihnen einige schnelle Leistungsgewinne bringen kann.
Beispiel:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
Wie Sie sehen können, hängt die Ausgabe von props.imageUrl
und ab props.username
. Wenn Sie in einer übergeordneten Komponente <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />
mit denselben Requisiten rendern , wird React render
jedes Mal aufgerufen , selbst wenn die Ausgabe genau gleich wäre. Denken Sie jedoch daran, dass React dom diffing implementiert, sodass das DOM nicht aktualisiert wird. Das Durchführen des Domdifferenzierens kann jedoch teuer sein, sodass es in diesem Szenario eine Verschwendung wäre.
Wenn die UserAvatar
Komponente PureComponent
stattdessen erweitert wird, wird ein flacher Vergleich durchgeführt. Und weil Requisiten und nextProps gleich sind, render
werden sie überhaupt nicht aufgerufen.
Anmerkungen zur Definition von "rein" in React:
Im Allgemeinen ist eine "reine Funktion" eine Funktion, die bei gleicher Eingabe immer das gleiche Ergebnis liefert. Die Ausgabe (für React wird dies von der render
Methode zurückgegeben) 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 "zustandslos" als eine Komponente bezeichnen, die niemals aufruft this.setState
und nicht verwendet this.state
.
Tatsächlich können Sie in a PureComponent
immer noch Nebenwirkungen während der Lebenszyklusmethoden ausführen. Zum Beispiel könnten Sie eine Ajax-Anfrage nach innen senden componentDidMount
oder eine DOM-Berechnung durchführen, um die Höhe eines Divs innerhalb dynamisch anzupassen render
.
Die Definition "Dumme Komponenten" hat eine "praktischere" Bedeutung (zumindest nach meinem Verständnis): Einer dummen Komponente wird "gesagt", was von einer übergeordneten Komponente über Requisiten zu tun ist, und sie weiß nicht, wie man Dinge macht, sondern verwendet Requisiten Rückrufe stattdessen.
Beispiel eines "smart" 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>
}
}
Beispiel eines "dummen" AvatarComponent
:
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
Am Ende würde ich sagen, dass "dumm", "staatenlos" und "rein" ganz unterschiedliche Konzepte sind, die sich manchmal überschneiden können, aber nicht unbedingt, abhängig hauptsächlich von Ihrem Anwendungsfall.
props
. Beispiel .PureComponent
sollten Sie nicht implementierenshouldComponentUpdate()
. Sie sollten eine Warnung sehen, wenn Sie dies tatsächlich tun.PureComponent
Komponenten zu verwenden, die über verschachtelte Objekt- / Array-Eigenschaften verfügen. Natürlich muss man sich bewusst sein, was passiert. Wenn ich das richtig verstehe, wenn Sie Requisiten / Status nicht direkt (was React versucht, Sie daran zu hindern, mit Warnungen umzugehen) oder über eine externe Bibliothek mutieren, sollten Sie sie mit AusnahmePureComponent
vonComponent
fast überall verwenden können ... mit Ausnahme von sehr einfachen Komponenten, bei denen es tatsächlich schneller sein kann, sie NICHT zu verwenden - siehe news.ycombinator.com/item?id=14418576Ich bin kein Genie überreagieren, aber nach 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 zum Rendern des Wiederholungselements der übergeordneten Komponente verwendet werden, z. B. zum Rendern der Textliste, in der nur die Informationen angezeigt werden und keine Aktionen ausgeführt werden müssen.
Reine Komponente - Dies sind die Elemente, die einen Lebenszyklus haben und immer das gleiche Ergebnis liefern, 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 zur Ausführung von Operationen verwendet werden, die sich nur auf sich selbst auswirken. Eine solche Anzeige einer Liste von Benutzerkarten oder einer Liste von Produktkarten (grundlegende Produktinformationen) und nur eine Aktion, die der Benutzer ausführen kann, ist das Klicken, um die Detailseite anzuzeigen oder dem Warenkorb hinzuzufügen.
Normale Komponenten oder komplexe Komponenten - Ich habe den Begriff komplexe Komponente verwendet, da dies normalerweise Komponenten auf Seitenebene sind und aus vielen untergeordneten Komponenten bestehen. Da sich jedes untergeordnete Element auf seine eigene Weise verhalten kann, können Sie nicht 100% sicher sein, dass dies der Fall ist Rendern Sie das gleiche Ergebnis für den angegebenen Status. Wie gesagt, normalerweise sollten diese als Containerkomponenten verwendet werden
quelle
PureComponent
Komponenten auf Stammebene und Komponenten in der Nähe der Spitze Ihrer Hierarchie werden normalerweise die größten Leistungssteigerungen erzielt. Natürlich müssen Sie vermeiden, Requisiten zu mutieren und direkt anzugeben, damit reine Komponenten korrekt funktionieren, aber das direkte Mutieren von Objekten ist in React sowieso ein Anti-Pattern.React.Component
ist die Standardkomponente "normal". Sie deklarieren sie mit demclass
Schlüsselwort undextends React.Component
. Stellen Sie sich diese als Klasse vor, mit Lebenszyklusmethoden, Ereignishandlern und anderen Methoden.React.PureComponent
ist eineReact.Component
, dieshouldComponentUpdate()
mit einer Funktion implementiert wird , die einen flachen Vergleich ihrerprops
und durchführtstate
. Sie müssen verwenden,forceUpdate()
wenn Sie wissen, dass die Komponente Requisiten oder verschachtelte Statusdaten enthält, die sich geändert haben, und Sie sie erneut rendern möchten. Sie sind also nicht besonders gut, wenn Sie Komponenten zum erneuten Rendern benötigen, wenn Arrays oder Objekte, die Sie als Requisiten übergeben oder in Ihrem Status festlegen, geändert werden.Funktionskomponenten sind solche, die keine Lebenszyklusfunktionen haben. Sie sind angeblich staatenlos, aber sie sind so schön und sauber, dass wir jetzt Haken haben (seit React 16.8), damit Sie immer noch einen Zustand haben können. Ich denke, sie sind nur "saubere Komponenten".
quelle