¿Cuál es la mejor manera de actualizar un objeto en una matriz en ReactJS?

Resuelto waterlooalex asked hace 9 años • 4 respuestas

Si tiene una matriz como parte de su estado y esa matriz contiene objetos, ¿cuál es una manera fácil de actualizar el estado con un cambio en uno de esos objetos?

Ejemplo, modificado del tutorial sobre reaccionar:

var CommentBox = React.createClass({
  getInitialState: function() {
    return {data: [
      { id: 1, author: "john", text: "foo" },
      { id: 2, author: "bob", text: "bar" }
    ]};
  },
  handleCommentEdit: function(id, text) {
    var existingComment = this.state.data.filter({ function(c) { c.id == id; }).first();
    var updatedComments = ??; // not sure how to do this  

    this.setState({data: updatedComments});
  }
}
waterlooalex avatar Jan 24 '15 08:01 waterlooalex
Aceptado

Me gusta bastante hacer esto con Object.assign en lugar de los ayudantes de inmutabilidad.

handleCommentEdit: function(id, text) {
    this.setState({
      data: this.state.data.map(el => (el.id === id ? Object.assign({}, el, { text }) : el))
    });
}

Simplemente creo que esto es mucho más conciso que el empalme y no requiere conocer un índice o manejar explícitamente el caso de no encontrado.

Si te apetece todo ES2018, también puedes hacerlo con spread en lugar deObject.assign

this.setState({
  data: this.state.data.map(el => (el.id === id ? {...el, text} : el))
});
undefined avatar Oct 02 '2017 02:10 undefined

Al actualizar el estado, la parte clave es tratarlo como si fuera inmutable. Cualquier solución funcionaría bien si puedes garantizarla.

Aquí está mi solución usando immutability-helper :

jsFiddle :

  var update = require('immutability-helper');

  handleCommentEdit: function(id, text) {
    var data = this.state.data;
    var commentIndex = data.findIndex(function(c) { 
        return c.id == id; 
    });

    var updatedComment = update(data[commentIndex], {text: {$set: text}}); 
    
    var newData = update(data, {
        $splice: [[commentIndex, 1, updatedComment]]
    });
    this.setState({data: newData});
  },

Las siguientes preguntas sobre matrices estatales también pueden ayudar:

  • Modificación correcta de matrices de estados en ReactJS
  • ¿Cuál es la forma preferida de mutar un estado de React?
nilgun avatar Jan 24 '2015 10:01 nilgun

Estoy tratando de explicar mejor cómo hacer esto Y qué está pasando.

  • Primero, busque el índice del elemento que está reemplazando en la matriz de estado.
  • En segundo lugar, updateel elemento en ese índice.
  • Tercero, llama setStatecon la nueva colección.
import update from 'immutability-helper';

// this.state = { employees: [{id: 1, name: 'Obama'}, {id: 2, name: 'Trump'}] } 

updateEmployee(employee) {
    const index = this.state.employees.findIndex((emp) => emp.id === employee.id);
    const updatedEmployees = update(this.state.employees, {$splice: [[index, 1, employee]]});  // array.splice(start, deleteCount, item1)
    this.setState({employees: updatedEmployees});
}

Editar: hay una manera mucho mejor de hacer esto sin una biblioteca de terceros

const index = this.state.employees.findIndex(emp => emp.id === employee.id);
employees = [...this.state.employees]; // important to create a copy, otherwise you'll modify state outside of setState call
employees[index] = employee;
this.setState({employees});
daino3 avatar Oct 15 '2017 23:10 daino3

Puedes hacer esto de varias maneras, te mostraré la que yo usé principalmente. Cuando trabajo con matrices en reaccionar, generalmente paso un atributo personalizado con el valor de índice actual; en el siguiente ejemplo, pasé el atributo de índice de datos, los datos son la convención html 5.

Ex:

//handleChange method.
handleChange(e){
  const {name, value} = e,
        index = e.target.getAttribute('data-index'), //custom attribute value
        updatedObj = Object.assign({}, this.state.arr[i],{[name]: value});
      
  //update state value.
  this.setState({
    arr: [
      ...this.state.arr.slice(0, index),
      updatedObj,
      ...this.state.arr.slice(index + 1)
    ]
  })
  }
Expandir fragmento

Umair Ahmed avatar May 16 '2017 15:05 Umair Ahmed