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.