反应:有效更新阵列状态

React: Efficient updating of array state

本文关键字:阵列 状态 更新 有效 反应      更新时间:2023-09-26

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

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

我知道标准解决方案是使用浅层复制,但这实际上只是浅层数组的复制。在我的情况下,它不是,所以浅层复制在反应意义上是"错误的",因为它会改变状态。那么,一个人应该如何处理这个问题呢?我可以使用浅层副本就可以了,但它感觉很脏并且在技术上是错误的。

编辑:或者澄清一下:如果我只使用浅拷贝的东西并确保告诉 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!

只要你把所有对象都看作不可变的(即,如果你需要更改一个属性,先做一个浅拷贝),你就不会出错。例如:

起始状态:

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 的不可变性助手。

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