Was ist der bevorzugte Weg, um einen Reaktionszustand zu mutieren?

97

Angenommen, ich habe eine Liste mit einfachen Objekten in meinem this.state.list, mit denen ich dann eine Liste mit untergeordneten Objekten rendern kann. Was ist dann der richtige Weg, um ein Objekt einzufügen this.state.list?

Im Folgenden ist der einzige Weg, wie ich denke, dass es funktionieren wird, da Sie das nicht this.statedirekt mutieren können, wie im Dokument erwähnt.

this._list.push(newObject):
this.setState({list: this._list});

Das scheint mir hässlich. Gibt es einen besseren Weg?

Khoi
quelle
Mögliches Duplikat der korrekten Änderung von Status-Arrays in ReactJS , die Zusammenführung anfordert
Brigand
Bei all diesen Antworten geht es darum, einem Array ein Element hinzuzufügen. Aber was ist mit dem Entfernen eines Elements? Oder einfach das Array komplett auf ein neues zurücksetzen?
Augustin Riedinger

Antworten:

165

concat Gibt ein neues Array zurück, damit Sie dies tun können

this.setState({list: this.state.list.concat([newObject])});

Eine weitere Alternative ist der Unveränderlichkeitshelfer von React

  var newState = React.addons.update(this.state, {
      list : {
        $push : [newObject]
      }
  });

  this.setState(newState);
Haufen
quelle
6
concatnimmt ein Array, also wirst du wollen this.state.list.concat([newObject]).
Sophie Alpert
@ BenAlpert funktioniert für mich in Chrome. Wollen Sie damit sagen, dass dies kein Standardverhalten ist?
Haufen
6
@Heap Nun, wenn Sie ein Nicht-Array übergeben, concatwird es in ein Array eingeschlossen, aber es ist besser, das Array selbst hinzuzufügen, um explizit zu sein: Wenn Sie das nächste Element haben [[1,2], [3,4]]und hinzufügen möchten [5,6], müssen Sie es .concat([[5,6]])anders machen Ich werde mit enden [[1,2], [3,4], 5, 6].
Sophie Alpert
2
So sehr ich die Idee hinter den Unveränderlichkeitshilfen schätze (und ich werde sie möglicherweise trotzdem verwenden), ist es Array.concatsicher besser, eine weitere Bibliothek hinzuzufügen.
Shawn Erquhart
1
Wenn Sie this.setState mit einem von this.state abgeleiteten Wert aufrufen, treten Probleme mit der Stapelverarbeitung von Updates auf. Siehe stackoverflow.com/a/41445812/1998186, das auf eine jsfiddle verweist, die das auftretende Problem anzeigt.
NealeU
40

setState () kann mit einer Funktion als Parameter aufgerufen werden:

this.setState((state) => ({ list: state.list.concat(newObj) }))

oder in ES5:

this.setState(function(state) {
  return {
   list: state.list.concat(newObj)
  }
})
Nyalab
quelle
2
@Arian: React führt die erforderlichen DOM-Mutationsanweisungen aus, die erforderlich sind, um nur die neu hinzugefügten Elemente zu rendern. Angesichts der Tatsache, dass Sie neu hinzugefügte Elemente sind, ändert sich natürlich nichts an der Darstellung der vorherigen Elemente.
Jose Browne
1
Dies ist eine fantastische Antwort und fühlt sich so viel sauberer an, als ein Array zu verketten, nur um einen Push auszuführen, obwohl das meine Meinung ist.
Matt Styles
2
@ Nyalab sollten Sie den Funktionskörper nicht in Klammern setzen? So wie es jetzt in Ihrem Beispiel steht, würden die geschweiften Klammern nach dem fetten Pfeil einen Block starten, kein Objekt. So etwas wie das:this.setState((state) => ({ list: state.list.push(newObj) }))
Kumarshar
3
Wie funktioniert dieser Code? Die Push-Methode gibt ein zurück NUMBER, das auf die listVariable gesetzt wird
kumarharsh
1
Sie könnten auch einen Splat verwenden:this.setState((state) => ({ list: [...state.list, newObj] }))
Amöbe
19

Update 2016

Mit ES6 können Sie Folgendes verwenden:

this.setState({ list: [...this.state.list, ...newObject] });
Ashish Chaudhary
quelle
5
...[newObject]ist das gleiche wie gerade newObject.
Amöbe
2
Dies funktioniert nicht für gestapelte Updates. Siehe mein Beispiel unter stackoverflow.com/a/41445812/1998186 .
NealeU