ReactJS: Warum ist das Übergeben des Komponenten-Anfangszustands als Requisite ein Anti-Muster?

78

Ich habe mit Hilfe von SocketIO ein kleines ReactJS-Dashboard für Live-Updates erstellt. Obwohl das Dashboard aktualisiert wird, stört es mich, dass ich nicht ganz sicher bin, ob ich es richtig gemacht habe.

Was mich am meisten nervt, sind die Requisiten in getInitialState als Anti-Pattern- Post. Ich habe ein Dashboard erstellt, das Live-Updates von einem Server erhält und keine Benutzerinteraktion erfordert, außer das Laden der Seite. Nach dem, was ich gelesen habe, this.statesollte es Dinge enthalten, die bestimmen, ob die Komponente neu gerendert werden soll, und this.props... ich weiß es noch nicht.

Wenn Sie jedoch zum ersten Mal anrufen React.render(<MyComponent />, ...), können Sie nur Requisiten übergeben. In meinem Fall erhalte ich alle Daten vom Server, sodass die ersten Requisiten this.statesowieso landen . Alle meine Komponenten haben also ungefähr so:

getInitialState: function() {
    return {
        progress: this.props.progress,
        latest_update: this.props.latest_update,
        nearest_center: this.props.nearest_center
    }
}

Was, sofern ich den oben genannten Blog-Beitrag nicht falsch interpretiert habe, ein Anti-Muster ist. Aber ich sehe keine andere Möglichkeit, den Status in die Komponente einzufügen, und ich verstehe nicht, warum es sich um ein Anti-Pattern handelt, es sei denn, ich beschrifte alle meine Requisiten neu, initialum ihnen vorangestellt zu werden. Wenn überhaupt, denke ich, dass dies ein Anti-Muster ist, weil ich jetzt mehr Variablen im Auge behalten muss als zuvor (die mit initialund ohne).

Charmeleon
quelle
1
Im Jahr 2017 demonstriert Facebook die Verwendung von Requisiten, um den Anfangszustand in ihrer Dokumentation festzulegen
Rohmer
1
@ Rohmers Link enthält einen Link zu Sie benötigen wahrscheinlich keinen abgeleiteten Status , in dem die Alternativen ausführlich besprochen werden und was zu vermeiden ist.
ToolmakerSteve

Antworten:

94

Haftungsausschluss : Als ich diese Frage beantwortete, lernte ich Vanilla Flux zu implementieren und war etwas skeptisch. Später habe ich alles auf Redux migriert. Also ein Rat: Gehen Sie einfach mit Redux oder MobX. Wahrscheinlich brauchen Sie nicht einmal mehr die Antwort auf diese Frage (außer für die Wissenschaft).

Das Übergeben des Anfangszustands an eine Komponente als propist ein Anti-Pattern, da die getInitialStateMethode nur beim ersten Rendern der Komponente aufgerufen wird. Das heißt, wenn Sie diese Komponente erneut rendern und einen anderen Wert als übergeben prop, reagiert die Komponente nicht entsprechend, da die Komponente den Status vom ersten Rendern an beibehält. Es ist sehr fehleranfällig.

Und hier ist, was Sie tun sollten:

Versuchen Sie, Ihre Komponenten so zustandslos wie möglich zu machen. Zustandslose Komponenten sind einfacher zu testen, da sie eine Ausgabe basierend auf einer Eingabe rendern . So einfach ist das.

Aber hey ... meine Komponentendaten ändern sich ... ich kann sie nicht zustandslos machen

Ja, das können Sie für die meisten. Wählen Sie dazu eine äußere Komponente als Staatsinhaber aus. Anhand Ihres Beispiels können Sie eine DashboardKomponente erstellen , die die Daten enthält, und eine WidgetKomponente, die vollständig zustandslos ist. Der Dashboardist dafür verantwortlich, alle Daten abzurufen und dann mehrere zu rendern Widgets, die alles erhalten, was sie benötigen props.

Aber meine Widgets haben einen Status. Der Benutzer kann sie konfigurieren. Wie mache ich sie staatenlos?

Sie Widgetkönnen Ereignisse verfügbar machen Dashboard, die Widgetbei der Behandlung dazu führen, dass sich der darin enthaltene Status ändert und alle erneut gerendert werden. Sie erstellen "Ereignisse" in Ihrem, Widgetindem Sie propsdiese eine Funktion erhalten lassen.

Ok, jetzt behält Dashboard den Status bei, aber wie übergebe ich den Anfangsstatus?

Sie haben zwei Möglichkeiten. Am empfehlenswertesten ist, dass Sie in der Dashboard getInitialStateMethode einen Ajax-Aufruf ausführen, um den Anfangsstatus vom Server abzurufen. Sie können auch Flux verwenden , eine komplexere Methode zum Verwalten von Daten. Flux ist eher ein Muster als eine Implementierung. Sie können reinen Flux mit der Facebook-Implementierung von verwenden Dispatcher, aber Sie können Implementierungen von Drittanbietern wie Redux , Alt oder Fluxxor verwenden .

Alternativ können Sie diesen Anfangszustand als propan übergeben Dashboardund explizit deklarieren, dass dies nur der Anfangszustand ist. Wie initialDatazum Beispiel. Wenn Sie diesen Pfad wählen, können Sie ihm später keinen anderen Anfangszustand übergeben, da er sich den Zustand nach dem ersten Rendern "merkt".

OBS

Sie sind in Ihren Definitionen nicht ganz richtig.

Der Status wird verwendet, um veränderbare Daten zu speichern, dh Daten, die sich während des Komponentenlebenszyklus ändern werden. Änderungen im Status sollten über die setStateMethode vorgenommen werden und führen dazu, dass die Komponente erneut gerendert wird.

Requisiten werden verwendet, um unveränderliche Daten an die Komponenten weiterzugeben. Sie sollten sich während des Komponentenlebenszyklus nicht ändern. Komponenten, die nur Requisiten verwenden, sind zustandslos.

Dies ist eine relevante Quelle zum Thema "Übergeben des Anfangszustands an Komponenten".

André Pena
quelle
es wird sehr gut beschrieben, aber ... wie immer ist es ein "aber". Was ist, wenn ich eine Komponente habe, die ein Array von Bildern abruft und untergeordnete Komponenten mit Miniaturansichten und einem Onlick-Ereignis erstellt, wodurch sich das große Bild in dieser Komponente ändern sollte? Die Bilder befinden sich nicht im Status, daher kann ich keine andere Komponente verwenden, um sie zu warten. Die Bilder sind lokal und ich benötige einen lokalen Status, um sie zu verwalten, der als großes Bild angezeigt werden soll. Ich würde gerne Requisiten im Status verwenden, aber Warnung erhalten: setState (...): Kann während eines vorhandenen Statusübergangs (z. B. innerhalb render) nicht aktualisiert werden . Rendermethoden sollten eine reine Funktion von Requisiten und Zustand sein.
Kania
10
Also, eine Meinung zur Verwendung componentWillReceiveProps(nextProps), um den Status festzulegen?
Alejandro
1
componentWillRecieveProps () ist ab 16.3 veraltet, also ... Nein. Verwenden Sie es nicht.
Rap
@Alejandro - Sie benötigen wahrscheinlich keinen abgeleiteten Status. Dies ist eine ausführliche Erklärung der Fallstricke bei der Verwendung (veraltet) componentWillReceivePropsoder deren (nicht veraltet) Ersetzung getDerivedStateFromProps. Fazit: Der Artikel zeigt mehrere alternative Lösungen, die keine dieser Methoden aufrufen, und erklärt, warum diese Alternativen stattdessen verwendet werden.
ToolmakerSteve