React:有效更新数组状态

IT技术 javascript reactjs
2021-05-21 03:31:58

React 的基本思想之一是状态更改应该始终且仅通过this.setState(...)而不是手动操作状态发生但是对于状态是一个深数组的情况,所以一个对象文字数组(实际上是一些 JSON 数据),更新该状态变得非常昂贵。如果我只想更新这样一个数组的一个元素,代码将类似于以下内容。

handleChange(index, newElement){
    var newStateArray = _.cloneDeep(this.state.myArray);
    newStateArray[index] = newElement;
    this.setState({myArray: newStateArray });
}

我知道标准的解决方案是使用浅复制,但这只是浅数组的副本。在我的情况下不是,所以浅复制在react意义上是“错误的”,因为它会改变状态。那么究竟应该如何处理呢?我可以只使用浅拷贝并且它可以工作,但是感觉很脏并且在技术上是错误的。

编辑:或者澄清一下:如果我只使用浅拷贝并确保告诉 React 手动更新,会不会有什么不好的事情发生?

编辑:哦,这似乎已经解决了。浅拷贝并不像我想象的那样工作。我是 JS 新手,请原谅。以供参考:

var a = [{a:1}, {b:2}, {c:3}]
var b = a.slice();
b[0] = 42; // I thought this would change a, but it doesn't!
2个回答

如果您将所有对象视为不可变的(即,如果您需要更改属性,请先制作一个浅拷贝),您就不会出错。例如:

启动状态:

var A = {
    foo: 3,
    bar: 7
};
var B = {
    baz: 11,
    boop: 5
};
var C = {
    myA: A,
    myB: B
};

假设我们要更改 C->myB->boop。A 中没有任何变化,因此我们不需要复制,但我们确实需要复制 B 和 C:

var newB = {
    baz: B.baz,
    boop: 1000000 // we have to update this in B, so we need a new B
};
var newC = {
    myA: C.myA,
    myB: newB    // we have to update this in C, so we need a new C
};

(显然,您会使用浅复制来制作每个部分的副本,然后在顶部分配更改;为了清晰起见,我只是手动写出副本)

当我们newC作为新状态提交时,它将只共享没有改变的部分(在本例中为 A),这很好,因为它们总是作为不可变对象处理。

概括地说,当您更改任何属性时,您需要制作包含该属性的对象的浅表副本,以及对象的父级及其父级的父级等,一直返回到您的根节点。您也可以以完全相同的方式考虑数组;为此,它们只是具有编号属性的对象。

如果您在进行更改的任何地方都遵循这些规则,那么您的浅层数组副本将可以正常工作。这适用于任何有状态历史的情况,而不仅仅是 reactjs。

请参阅 React 的Immutability Helpers

handleChange(index, newElement){
    var newStateArray = update(this.state.myArray, {
        [index]: {b: {$set: newElement.target.value} }
    });
    this.setState({myArray: newStateArray });
}