【问题标题】:Whats the best way to update an object in an array in ReactJS?在 ReactJS 中更新数组中的对象的最佳方法是什么?
【发布时间】:2015-03-23 03:54:55
【问题描述】:

如果您有一个数组作为状态的一部分,并且该数组包含对象,那么有什么简单的方法可以通过更改其中一个对象来更新状态?

示例,改编自 react 教程:

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

【问题讨论】:

标签: javascript reactjs


【解决方案1】:

在更新状态时,关键部分是将其视为不可变的。如果你能保证,任何解决方案都可以正常工作。

这是我使用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});
  },

以下有关状态数组的问题也可能有所帮助:

【讨论】:

  • 我最终使用 map 来更新数组。 var newData = this.state.data.map(function(c) { return c.id == id ? React.addons.update(c, update) : c; });
【解决方案2】:

我很喜欢用 Object.assign 来做这件事,而不是使用不变性助手。

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

我只是认为这比 splice 更简洁,并且不需要知道索引或显式处理未找到的情况。

如果你感觉全部是 ES2018,你也可以用 spread 代替 Object.assign

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

【讨论】:

  • 愿力量与你同在@Luke。这很整洁。
  • 我更喜欢这段代码,看起来不那么冗长。但是,代码缺少映射函数的右括号
  • @CraigMyles 很好,我会修复它
  • 喜欢您的解决方案:简短且不依赖第三方库。
  • 很好的答案,谢谢!由于你不应该访问 setState 中的状态,这是一个更安全的版本:this.setState(prevState => ({ data: prevState.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});
}

编辑:有一个更好的方法可以做到这一点,无需 3rd 方库

    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】:

    您可以通过多种方式做到这一点,我将向您展示我最常用的方式。当我在 react 中处理数组时,我通常会传递一个具有当前索引值的自定义属性,在下面的示例中,我传递了 data-index 属性,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)
        ]
      })
      }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-06
      • 1970-01-01
      相关资源
      最近更新 更多