¿Cuál es la mejor manera de actualizar un objeto en una matriz en ReactJS?
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});
}
}
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))
});
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?
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,
update
el elemento en ese índice. - Tercero, llama
setState
con 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});
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)
]
})
}