¿Cuál es la forma preferida de mutar un estado de React?

97

Digamos que tengo una lista de objetos simples en mi this.state.listque luego puedo usar para representar una lista de niños. Entonces, ¿cuál es la forma correcta de insertar un objeto this.state.list?

A continuación se muestra la única forma en que creo que funcionará porque no puede mutar this.statedirectamente como se menciona en el documento.

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

Esto me parece feo. ¿Existe una forma mejor?

Khoi
fuente
posible duplicado de la modificación correcta de matrices de estado en ReactJS , solicitando fusión
Brigand
Todas esas respuestas tratan de agregar un elemento a una matriz. Pero, ¿qué hay de quitarle un elemento? ¿O simplemente para restablecer completamente la matriz a una nueva?
Augustin Riedinger

Respuestas:

165

concat devuelve una nueva matriz, por lo que puede hacer

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

otra alternativa es el ayudante de inmutabilidad de React

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

  this.setState(newState);
Montón
fuente
6
concattoma una matriz, así que querrás this.state.list.concat([newObject]).
Sophie Alpert
@BenAlpert funciona para mí en Chrome, ¿estás diciendo que este es un comportamiento no estándar?
Heap
6
@Heap Bueno, si le pasa una matriz que concatno sea, la envolverá en una matriz, pero es mejor agregar la matriz usted mismo para ser explícito: si tiene [[1,2], [3,4]]y desea agregar [5,6]como el siguiente elemento, debe hacer .concat([[5,6]])otra cosa Terminará con [[1,2], [3,4], 5, 6].
Sophie Alpert
2
Por mucho que aprecio la idea detrás de los ayudantes de inmutabilidad (y puedo terminar usándola de todos modos), Array.concatseguro que es mejor agregar otra biblioteca.
Shawn Erquhart
1
Llamar a this.setState con un valor derivado de this.state le hará caer en problemas de actualización por lotes. Consulte stackoverflow.com/a/41445812/1998186 que se vincula a un jsfiddle que muestra el problema que obtendrá.
NealeU
40

setState () se puede llamar con una función como parámetro:

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

o en ES5:

this.setState(function(state) {
  return {
   list: state.list.concat(newObj)
  }
})
Nyalab
fuente
2
@Arian: React ejecutará las instrucciones de mutación DOM requeridas necesarias para representar solo los elementos recién agregados. Dado, por supuesto, que sus elementos recién agregados no cambian la forma en que se procesaron los elementos anteriores.
Jose Browne
1
Esta es una respuesta fantástica y se siente mucho más limpia que la concatenación de la matriz solo para realizar un empuje, aunque supongo que esa es la opinión.
Matt Styles
2
@Nyalab, ¿no debería envolver el cuerpo de la función entre paréntesis? Tal como está ahora en su ejemplo, las llaves después de la flecha gruesa iniciarían un bloque, no un objeto. Algo como esto:this.setState((state) => ({ list: state.list.push(newObj) }))
kumarharsh
3
¿Cómo funciona este código? el método push devolverá a NUMBER, que se establecerá en la listvariable
kumarharsh
1
También puede utilizar un this.setState((state) => ({ list: [...state.list, newObj] }))
símbolo
19

Actualización 2016

Con ES6 puede utilizar:

this.setState({ list: [...this.state.list, ...newObject] });
Ashish Chaudhary
fuente
5
...[newObject]es lo mismo que just newObject.
amebe
2
Esto no funcionará para las actualizaciones por lotes. Vea mi ejemplo en stackoverflow.com/a/41445812/1998186 .
NealeU