Präsentations- und Containerkomponenten
Update von 2019: Ich habe diesen Artikel vor langer Zeit geschrieben und meine Ansichten haben sich seitdem weiterentwickelt. Insbesondere schlage ich nicht mehr vor, Ihre Komponenten so zu teilen. Wenn Sie es in Ihrer Codebasis natürlich finden, kann dieses Muster nützlich sein. Aber ich habe es viel zu oft ohne Notwendigkeit und mit fast dogmatischem Eifer durchgesetzt gesehen. Der Hauptgrund, warum ich es nützlich fand, war, dass ich komplexe zustandsbehaftete Logik von anderen Aspekten der Komponente trennen konnte. Haken lassen Sie mich das gleiche tun, ohne eine willkürliche Teilung. Dieser Text bleibt aus historischen Gründen intakt, aber nehmen Sie ihn nicht zu ernst.
Es gibt ein einfaches Muster, das ich beim Schreiben von React-Anwendungen immens nützlich finde. Wenn Sie React schon eine Weile machen, haben Sie es wahrscheinlich schon entdeckt. Dieser Artikel erklärt es gut, aber ich möchte noch ein paar Punkte hinzufügen.
Sie werden feststellen, dass Ihre Komponenten viel einfacher wiederzuverwenden sind, wenn Sie sie in zwei Kategorien unterteilen. Ich nenne sie Container- und Präsentationskomponenten *, aber ich höre auch Fett und dünn, klug und dumm, zustandsbehaftet und rein, Bildschirme und Komponenten usw. Diese sind nicht alle genau gleich, aber die Kernidee ist ähnlich.
Meine Präsentationskomponenten:
- Sind besorgt darüber, wie die Dinge aussehen.
- Kann sowohl Präsentations- als auch Containerkomponenten ** enthalten und verfügt normalerweise über eigene DOM-Markups und -Stile.
- Oft erlauben Eindämmung über diese.Requisite.Kinder.
- Haben keine Abhängigkeiten vom Rest der App, z. B. Flux-Aktionen oder Stores.
- Geben Sie nicht an, wie die Daten geladen oder mutiert werden.
- Empfangen Sie Daten und Rückrufe ausschließlich über Requisiten.
- Haben selten einen eigenen Status (wenn dies der Fall ist, handelt es sich eher um den UI-Status als um Daten).
- Werden als funktionale Komponenten geschrieben, es sei denn, sie benötigen Status-, Lebenszyklus-Hooks oder Leistungsoptimierungen.
- Beispiele: Seite, Sidebar, Story, userInfo, Liste.
Meine Container-Komponenten:
- Sind besorgt darüber, wie die Dinge funktionieren.
- Kann sowohl Präsentations- als auch Containerkomponenten ** enthalten, verfügt jedoch normalerweise über kein eigenes DOM-Markup, mit Ausnahme einiger umschließender Divs, und hat niemals Stile.
- Stellen Sie die Daten und das Verhalten für Präsentations- oder andere Containerkomponenten bereit.
- Rufen Sie Flux-Aktionen auf und stellen Sie diese als Rückrufe für die Präsentationskomponenten bereit.
- Sind oft zustandsbehaftet, da sie dazu neigen, als Datenquellen zu dienen.
- Werden normalerweise mit Komponenten höherer Ordnung wie connect() von React Redux , createContainer() von Relay oder Container generiert.create() von Flux Utils, anstatt von Hand geschrieben.
- Beispiele: UserPage, Followersidebar, StoryContainer, FollowedUserList.
Ich habe sie in verschiedenen Ordnern abgelegt, um diese Unterscheidung zu verdeutlichen.
Vorteile dieses Ansatzes
- Bessere Trennung von Bedenken. Sie verstehen Ihre App und Ihre Benutzeroberfläche besser, indem Sie Komponenten auf diese Weise schreiben.
- Bessere Wiederverwendbarkeit. Sie können dieselbe Präsentationskomponente mit völlig unterschiedlichen Statusquellen verwenden und diese in separate Containerkomponenten umwandeln, die weiter wiederverwendet werden können.
- Präsentationskomponenten sind im Wesentlichen die “Palette” Ihrer App. Sie können sie auf einer einzigen Seite platzieren und den Designer alle ihre Variationen optimieren lassen, ohne die Logik der App zu berühren. Sie können Screenshot-Regressionstests auf dieser Seite ausführen.
- Dies zwingt Sie, “Layout-Komponenten” wie Seitenleiste, Seite, Kontextmenü zu extrahieren und diese zu verwenden.Requisite.kinder, anstatt dasselbe Markup und Layout in mehreren Containerkomponenten zu duplizieren.
Denken Sie daran, dass Komponenten kein DOM ausgeben müssen. Sie müssen nur Kompositionsgrenzen zwischen UI-Anliegen angeben.
Profitieren Sie davon.
Wann Container einführen?
Ich schlage vor, dass Sie Ihre App zuerst nur mit Präsentationskomponenten erstellen. Schließlich werden Sie feststellen, dass Sie zu viele Requisiten an die Zwischenkomponenten weitergeben. Wenn Sie feststellen, dass einige Komponenten die empfangenen Requisiten nicht verwenden, sondern nur weiterleiten und Sie alle diese Zwischenkomponenten jedes Mal neu verkabeln müssen, wenn die untergeordneten Komponenten mehr Daten benötigen, ist es ein guter Zeitpunkt, einige Containerkomponenten einzuführen. Auf diese Weise können Sie die Daten und das Verhalten relativ zu den Blattkomponenten abrufen, ohne die nicht verwandten Komponenten in der Mitte des Baums zu belasten.
Dies ist ein fortlaufender Prozess des Refactorings, also versuchen Sie nicht, es beim ersten Mal richtig zu machen. Wenn Sie mit diesem Muster experimentieren, entwickeln Sie ein intuitives Gefühl dafür, wann es Zeit ist, einige Container zu extrahieren, genau wie Sie wissen, wann es Zeit ist, eine Funktion zu extrahieren. Meine kostenlose Redux Egghead-Serie könnte Ihnen auch dabei helfen!
Andere Dichotomien
Es ist wichtig, dass Sie verstehen, dass die Unterscheidung zwischen den Präsentationskomponenten und den Containern keine technische ist. Vielmehr ist es eine Unterscheidung in ihrem Zweck.
Im Gegensatz dazu sind hier ein paar verwandte (aber anders!) technische Unterschiede:
- Stateful und Stateless. Einige Komponenten verwenden die React setState () -Methode und andere nicht. Während Containerkomponenten tendenziell zustandsbehaftet sind und Präsentationskomponenten tendenziell zustandslos sind, ist dies keine harte Regel. Präsentationskomponenten können zustandsbehaftet sein, und Container können auch zustandslos sein.
- Klassen und Funktionen. Seit React 0.14 können Komponenten sowohl als Klassen als auch als Funktionen deklariert werden. Funktionale Komponenten sind einfacher zu definieren, es fehlen jedoch bestimmte Funktionen, die derzeit nur für Klassenkomponenten verfügbar sind. Einige dieser Einschränkungen können in Zukunft weggehen, aber sie existieren heute. Da funktionale Komponenten einfacher zu verstehen sind, empfehle ich Ihnen, sie zu verwenden, es sei denn, Sie benötigen Status-, Lebenszyklus-Hooks oder Leistungsoptimierungen, die derzeit nur für die Klassenkomponenten verfügbar sind.
- Rein und unrein. Die Leute sagen, dass eine Komponente rein ist, wenn garantiert wird, dass sie bei denselben Requisiten und demselben Status dasselbe Ergebnis liefert. Reine Komponenten können sowohl als Klassen als auch als Funktionen definiert werden und können sowohl zustandsbehaftet als auch zustandslos sein. Ein weiterer wichtiger Aspekt reiner Komponenten ist, dass sie nicht auf tiefe Mutationen in Requisiten oder Status angewiesen sind, sodass ihre Renderleistung durch einen flachen Vergleich in ihrem shouldComponentUpdate () -Hook optimiert werden kann. Derzeit können nur Klassen shouldComponentUpdate() definieren, aber das kann sich in Zukunft ändern.
Sowohl Präsentationskomponenten als auch Container können in einen dieser Eimer fallen. Nach meiner Erfahrung sind Präsentationskomponenten in der Regel zustandslose reine Funktionen, und Container sind in der Regel zustandsbehaftete reine Klassen. Dies ist jedoch keine Regel, sondern eine Beobachtung, und ich habe genau entgegengesetzte Fälle gesehen, die unter bestimmten Umständen Sinn machten.
Nehmen Sie die Trennung von Präsentations- und Containerkomponenten nicht als Dogma. Manchmal ist es egal oder es ist schwer, die Grenze zu ziehen. Wenn Sie sich nicht sicher sind, ob eine bestimmte Komponente präsentativ oder ein Container sein soll, ist es möglicherweise zu früh, sich zu entscheiden. Schwitzen Sie nicht!
Beispiel
Dieser Kern von Michael Chan nagelt es ziemlich fest.
Weiterführende Literatur
- Erste Schritte mit Redux
- Mixins sind tot, es lebe die Komposition
- Containerkomponenten
- Atomares Webdesign
- Erstellen des Facebook-Newsfeeds mit Relay
Fußnoten
* In einer früheren Version dieses Artikels nannte ich sie “intelligente” und “dumme” Komponenten, aber dies war zu hart für die Präsentationskomponenten und erklärte vor allem nicht wirklich den Unterschied in ihrem Zweck. Ich genieße die neuen Bedingungen viel besser, und ich hoffe, dass Sie es auch tun!
** In einer früheren Version dieses Artikels habe ich behauptet, dass Präsentationskomponenten nur andere Präsentationskomponenten enthalten sollten. Ich glaube nicht mehr, dass dies der Fall ist. Ob es sich bei einer Komponente um eine Präsentationskomponente oder einen Container handelt, ist das Implementierungsdetail. Sie sollten in der Lage sein, eine Präsentationskomponente durch einen Container zu ersetzen, ohne eine der Aufrufseiten zu ändern. Daher können sowohl Präsentations- als auch Containerkomponenten problemlos andere Präsentations- oder Containerkomponenten enthalten.