Ein Objekt im Status einer React-Komponente speichern?

75

Ist es möglich, ein Objekt im Status einer React-Komponente zu speichern? Wenn ja, wie können wir dann den Wert eines Schlüssels in diesem Objekt mit ändern setState? Ich denke, es ist syntaktisch nicht erlaubt, so etwas zu schreiben wie:

this.setState({ abc.xyz: 'new value' });

In ähnlicher Weise habe ich eine andere Frage: Ist es in Ordnung, eine Reihe von Variablen in einer React-Komponente zu haben, sodass sie in jeder Methode der Komponente verwendet werden können, anstatt sie in einem Zustand zu speichern?

Sie können ein einfaches Objekt erstellen, das alle diese Variablen enthält, und es auf Komponentenebene platzieren, genau wie Sie Methoden für die Komponente deklarieren würden.

Es ist sehr wahrscheinlich, dass Sie auf Situationen stoßen, in denen Sie viel Geschäftslogik in Ihren Code aufnehmen. Dazu müssen viele Variablen verwendet werden, deren Werte durch verschiedene Methoden geändert werden. Anschließend ändern Sie den Status der Komponente basierend auf diesen Werten.

Anstatt alle diese Variablen im Status zu belassen, behalten Sie nur die Variablen bei, deren Werte direkt in der Benutzeroberfläche wiedergegeben werden sollen.

Wenn dieser Ansatz besser ist als die erste Frage, die ich hier geschrieben habe, muss ich kein Objekt im Status speichern.

Rahul Dole
quelle

Antworten:

37

Zusätzlich zu Kirans Beitrag gibt es den Update-Helfer (früher ein React- Addon ). Dies kann mit npm mit installiert werdennpm install immutability-helper

import update from 'immutability-helper';

var abc = update(this.state.abc, {
   xyz: {$set: 'foo'}
});

this.setState({abc: abc});

Dadurch wird ein neues Objekt mit dem aktualisierten Wert erstellt, und andere Eigenschaften bleiben unverändert. Dies ist nützlicher, wenn Sie beispielsweise auf ein Array pushen und gleichzeitig einen anderen Wert festlegen müssen. Einige Leute benutzen es überall, weil es Unveränderlichkeit bietet.

Wenn Sie dies tun, können Sie Folgendes tun, um die Leistung von auszugleichen

shouldComponentUpdate: function(nextProps, nextState){
   return this.state.abc !== nextState.abc; 
   // and compare any props that might cause an update
}
Räuber
quelle
Ich stelle mir also vor, es wäre viel einfacher, den Status einfach in etwas anderem zu speichern this.stateund render()jederzeit anzurufen, wenn Sie etwas daran ändern. Wird das unter erfahrenen React-Entwicklern als absolutes No-No angesehen?
Andy
machen ist eine reine Funktion, ist es nicht wirklich tut nichts. Es wird durch Reagieren aufgerufen, wenn ein Update vorliegt, und Updates werden durch setState-Aufrufe verursacht. Best Practices besagen, dass Ihr Rendering dieselbe Ausgabe für dieselben Requisiten und denselben Status erzeugen sollte. Dadurch können Optimierungen wie das shouldComponentUpdate auch einfach sein.
Brigand
Wow, war ich so lange von SO weg? Tatsächlich habe ich einige grundlegende reaktive Tools verwendet, um aufzurufen, forceUpdate()wenn sich bestimmte Felder eines Backbone-Modells geändert haben. Aus diesem Grund kann ich einfach überschreiben shouldComponentUpdate, um false zurückzugeben. rendererzeugt immer noch die gleiche Ausgabe für den gleichen propsund "Zustand" (dh die Backbone-Modelle, in denen ich nichts speichere this.state).
Andy
1
@Sebastialonso require('react-addons-update')und natürlich installieren.
Brigand
1
Dieser Helfer scheint nun ein Vermächtnis zu sein, und diese Bibliothek wird stattdessen empfohlen: github.com/kolodny/immutability-helper
asiop
88
  1. this.setState({ abc.xyz: 'new value' });Syntax ist nicht erlaubt. Sie müssen das gesamte Objekt übergeben.

    this.setState({abc: {xyz: 'new value'}});
    

    Wenn Sie andere Variablen in abc haben

    var abc = this.state.abc;
    abc.xyz = 'new value';
    this.setState({abc: abc});
    
  2. Sie können gewöhnliche Variablen haben, wenn sie nicht auf this.props und angewiesen sind this.state.

kiran
quelle
13
Wenn Sie andere Eigenschaften im Objekt behalten möchten, ist eine Methode wie die Erweiterung des Unterstrichs hilfreich:this.setState({abc: _.extend(this.state.abc, {xyz: 'new value'})});
smhg
1
@smhg ist nicht ganz updateleistungsfähiger, da es Befehle zum Ändern komplexer Objekte innerhalb des Status unterstützt. Wenn Sie diese speziellen Funktionen nicht benötigen, bietet sie meiner Meinung nach _.extendeine viel sauberere Syntax, insbesondere für jemanden, der den Code später liest und mit dessen Zweck nicht vertraut ist update.
Zoltán
2
@smhg, um zu Object.assignIhrem hinzuzufügen, können Sie verwenden, wenn Ihr Browser ES6 unterstützt (oder nur eine Polyfüllung verwenden)
Jay
1
@kiran Wenn Sie ein komplexes Objekt auf eine Variable setzen, wird es NICHT kopiert, sondern es wird einfach erneut auf dasselbe Objekt verwiesen. Also, var abc = this.state.abc; abc.xyz = 'new value'; ist das gleiche wie this.state.abc.xyz='new value'
jasonseminara
1
Diese Antwort sieht verdächtig aus, als würde OP den Status direkt ändern, was ein großes Nein-Nein ist. Angenommen, es abcgibt nur primitive Felder, sollte die richtige erste Zeile lautenvar abc = { ...this.state.abc };
Chris G
46

Sie können ES6-Spread für vorherige Werte im Objekt verwenden, um ein Überschreiben zu vermeiden

this.setState({
     abc: {
            ...this.state.abc,
            xyz: 'new value'
           }
});
PranavPinarayi
quelle
15

this.setState({abc: {xyz: 'new value'}});wird NICHT funktionieren, da state.abcvollständig überschrieben, nicht zusammengeführt wird.

Das funktioniert bei mir:

this.setState((previousState) => {
  previousState.abc.xyz = 'blurg';
  return previousState;
});

Sofern ich die Dokumente nicht falsch lese, empfiehlt Facebook das oben genannte Format. https://facebook.github.io/react/docs/component-api.html

Außerdem ist der direkteste Weg ohne Mutationsstatus das direkte Kopieren mit dem ES6-Spread / Rest-Operator:

const newState = { ...this.state.abc }; // deconstruct state.abc into a new object-- effectively making a copy
newState.xyz = 'blurg';
this.setState(newState);
jasonseminara
quelle
Ich habe Ihren ersten Weg mit getestet componentDidUpdate()und er hat den vorherigen Status korrekt beibehalten, während er this.setState({[abc.xyz]: 'blurg'})den falschen vorherigen Status angegeben hat. Ich gehe also davon aus, dass er gut ist.
Martin Dawson
Der vorherige Status war nicht der vorherige Status. Es war der aktuelle Zustand, was falsch ist.
Martin Dawson
previousState.abc.xyz = 'blurg';mutiert den aktuellen Zustand, der ein Anti-Muster in React ist.
Emile Bergeron
8

Obwohl dies über einen Unveränderlichkeitshelfer oder ähnliches möglich ist, möchte ich meinem Code keine externen Abhängigkeiten hinzufügen, es sei denn, ich muss es wirklich tun. Wenn ich es tun muss, benutze ich Object.assign. Code:

this.setState({ abc : Object.assign({}, this.state.abc , {xyz: 'new value'})})

Kann auch für HTML-Ereignisattribute verwendet werden, Beispiel:

onChange={e => this.setState({ abc : Object.assign({}, this.state.abc, {xyz : 'new value'})})}
Ogglas
quelle
8

Einfachere Möglichkeit, dies in einer Codezeile zu tun

this.setState({ object: { ...this.state.object, objectVarToChange: newData } })
Kevin Danikowski
quelle