设置数组等于另一个数组或使用三个点之间的区别

Difference between setting array equal to another one, or using three dots

在 React 中使用钩子并使用数组作为状态时,我发现使用 setter 函数仅更新该状态数组的一个元素不会重新渲染组件。我是这样做的:

const [listCollapsed, setListCollapse] = useState(Array(props.list.length).fill(false));

const expandCollapse = (ind) => {
    let newListCollapsed = listCollapsed;
    newListCollapsed[ind] = !listCollapsed[ind];
    setListCollapse(newListCollapsed);

}

其中 expandCollapse 是在按下列表元素时调用的函数。我发现将函数的第一行更改为:

let newListCollapsed = [...listCollapsed];

成功了。我想知道对此的解释是什么。

您的第一个版本通过直接 修改 状态打破了 React 的主要规则之一(更多关于 in this part of the docs)。行

let newListCollapsed = listCollapsed;

只是使 newListCollapsedlistCollapsed 都引用同一个数组(用作状态的数组),不会 复制数组.当你这样做时,你会得到这样的结果:

state:Ref5461−−−−−−−−−−−−−−−−+
                              \      +−−−−−−−−−−−+ 
listCollapsed:Ref5461−−−−−−−−−−+−−−−>|  (array)  | 
                              /      +−−−−−−−−−−−+ 
newListCollapsed:Ref5461−−−−−+       | 0: false  | 
                                     | 1: false  | 
                                     | ...       | 
                                     +−−−−−−−−−−−+

所以

setListCollapse(newListCollapsed);

不执行任何操作,因为它设置的是状态已包含的相同数组。 React 没有看到任何变化。

但是这一行:

let newListCollapsed = [...listCollapsed];

将数组复制 到一个新数组中(使用扩展符号将其条目扩展到由 [] 文字创建的新数组中),所以你有:

state:Ref5461−−−−−−−−−−−−−−−−+
                              \      +−−−−−−−−−−−+ 
listCollapsed:Ref5461−−−−−−−−−−+−−−−>|  (array)  | 
                                     +−−−−−−−−−−−+ 
                                     | 0: false  | 
                                     | 1: false  | 
                                     | ...       | 
                                     +−−−−−−−−−−−+

                                     +−−−−−−−−−−−+ 
newListCollapsed:Ref8465−−−−−−−−−−−−>|  (array)  | 
                                     +−−−−−−−−−−−+ 
                                     | 0: false  | 
                                     | 1: false  | 
                                     | ...       | 
                                     +−−−−−−−−−−−+

所以当你调用 setListCollapse(newListCollapsed); 时,它不是一回事,并且发生了变化。这是正确的做法。

(这些图中的 Ref#### 值是概念性的。它们是两个数组的对象引用。对象引用告诉 JavaScript 引擎对象在哪里在内存中。您永远不会在代码中看到对象引用的实际值。)