Javascript 在反应状态替换数组中的对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39889009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 23:02:05  来源:igfitidea点击:

Replace object in array on react state

javascriptarraysreactjsecmascript-6immutability

提问by motleydev

This question might fall a little on the side of a "best practice" question, but please bear with me.

这个问题可能有点属于“最佳实践”问题,但请耐心等待。

Here is a portion of my state:

这是我状态的一部分:

this.state = {
  typeElements: {
    headers: [
        {
          name: "h1",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }, {
          name: "h2",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }, {
          name: "h3",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }...

What I need to do is REPLACE the object at a given index on the headers array.

我需要做的是在标头数组的给定索引处替换对象。

I don't know how to do that with the setState method as in this.setState(headers[1] = {obj})- but that's obviously invalid. My current method is creating a new array and clobbering the old one like this:

我不知道如何使用 setState 方法来做到这一点this.setState(headers[1] = {obj})- 但这显然是无效的。我目前的方法是创建一个新数组并像这样破坏旧数组:

_updateStyle(props) {
  let newState = Object.assign({}, this.state)
  newState.typeElements.headers[props.index] = props
  this.setState(newState)
};

For my small hacky project I guess it's OK but I feel like this is super heavy handed and would quickly lead to performance issues at any kind of scale.

对于我的小型 hacky 项目,我想这没问题,但我觉得这是超级笨拙的,并且会很快导致任何规模的性能问题。

回答by Robin Venneman

Updated: since this answer still gets upvotes, be aware that the previous answer below is outdated with modern JavaScript and React. The "update" addon is now legacy and "immutability-helper"can be used instead.

更新:由于这个答案仍然得到赞成,请注意下面的先前答案对于现代 JavaScript 和 React 来说已经过时了。“更新”插件现在是旧的,可以使用“不变性助手”代替。

The React docs also mention why immutability is importantso avoid mutating state. For immutable updates you can use Object.assign()or spread syntaxwhich needs to be done for every level of nesting, like in this example the nested headersobject and its array elements. In this particular example we can use the array index as key so it's possible to also use the spread operator to make a shallow clone of the array and assign a new object as value at given index in the cloned array.

React 文档还提到了为什么不变性很重要,因此避免改变状态。对于不可变更新,您可以使用Object.assign()传播需要为每个嵌套级别完成的语法,例如在此示例中嵌套headers对象及其数组元素。在这个特定的例子中,我们可以使用数组索引作为键,因此也可以使用扩展运算符来创建数组的浅层克隆,并在克隆数组中的给定索引处分配一个新对象作为值。

_updateStyle (props) {
  const { typeElements } = this.state;
  const updatedHeaders = [...typeElements.headers];
  updatedHeaders[props.index] = props;
  this.setState({
    ...this.state,
    typeElements: {
      ...typeElements,
      headers: updatedHeaders
    }
  ));
}

Another solution which doesn't require the spread syntax and is needed if we are not using the array index to find the object we want to replace, is using array.mapto create a new array and returning the new object instead of the old one at given index.

如果我们不使用数组索引来查找要替换的对象,则不需要展开语法的另一种解决方案是使用array.map创建一个新数组并在给定索引处返回新对象而不是旧对象.

  const updatedHeaders = typeElements.headers.map((obj, index) => {
    return index === props.index ? props : obj;
  });

Similar examples in the Redux docs also explain "immutable update patterns".

Redux 文档中的类似示例也解释了“不可变更新模式”

React has some immutability helpers for this, which is explained in the docs: https://facebook.github.io/react/docs/update.html

In your case you could use the $splice command to remove one item and add the new one at given index, for example:

_updateStyle (props) {
  this.setState(update(this.state.typeElements, 
    { $splice: [[props.index, 1, props]] }
  ));
}

React 对此有一些不变性助手,这在文档中进行了解释:https: //facebook.github.io/react/docs/update.html

在您的情况下,您可以使用 $splice 命令删除一项并在给定索引处添加新项,例如:

_updateStyle (props) {
  this.setState(update(this.state.typeElements, 
    { $splice: [[props.index, 1, props]] }
  ));
}

回答by ChaosPredictor

use immutability-helper

使用不变性助手

you can find nice examples there

你可以在那里找到很好的例子

回答by daino3

Offering a better explanation of how to accomplish this.

提供有关如何完成此操作的更好解释。

  • First, find the index of the element you're replacing in the state array.
  • Second, updatethe element at that index
  • Third, call setStatewith the new collection
  • 首先,在状态数组中找到要替换的元素的索引。
  • 其次,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});
}

回答by Artru

Object.Assign uses shallow copy, not deep copy.

Object.Assign 使用浅拷贝,而不是深拷贝。

Please be aware that in your example Object.assign({}, this.state)copies only links to the nearest children of the state, i.e. to typeElements, but headersarray is not copied.

请注意,在您的示例中,Object.assign({}, this.state)仅复制到 的最近子项的链接state,即到typeElements,但headers不会复制数组。

There is a syntactic sugar ...in ES6 for Object.Assign, Babel has the special addon transform-object-rest-spread.

...ES6 中有一个Object.Assign的语法糖,Babel 有一个特殊的插件transform-object-rest-spread

let newHeaders = { ...this.state.typeElements.headers};
newHeaders[index] = props.Something;

let newState = {...state, typeElements: { newHeaders }};