Подтвердить что ты не робот

Каков наилучший способ обновления объекта в массиве в ReactJS?

Если у вас есть массив как часть вашего состояния, и этот массив содержит объекты, то какой простой способ обновить состояние с изменением одного из этих объектов?

Пример, измененный из учебника по реагированию:

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});
  }
}
4b9b3361

Ответ 1

При обновлении состояния ключевая часть должна обрабатывать ее, как если бы она была неизменной. Любое решение будет работать нормально, если вы можете это гарантировать.

Вот мое решение, используя immutability-helper:

jsFiddle: http://jsfiddle.net/eLmwf14a/

  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});
  },

Следующие вопросы о государственных массивах также могут помочь:

Ответ 2

Мне очень нравится делать это с Object.assign, а не с помощниками неизменяемости.

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

Я просто думаю, что это гораздо более лаконично, чем сплайсинг и не требует знания индекса или явной обработки не найденного случая.

Если вы чувствуете все ES2018, вы также можете сделать это с помощью распространения вместо Object.assign

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

Ответ 3

Попытка очистить/объяснить лучше, как это сделать и что происходит.

  • Сначала найдите индекс элемента, который вы заменяете, в массиве состояний.
  • Во-вторых, update элемент по этому индексу
  • В-третьих, вызовите setState с новой коллекцией
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});
}

Изменение: есть гораздо лучший способ сделать это без сторонней библиотеки

    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});

Ответ 4

Вы можете сделать это несколькими способами, я собираюсь показать вам, что я в основном использовал. Когда я работаю с массивами в реакции, обычно я передаю пользовательский атрибут с текущим значением индекса, в приведенном ниже примере я передал атрибут индекса data-, data- - соглашение html 5.

Пример:

//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)
    ]
  })
  }