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

Geo*_*mar 2 javascript reactjs spread-syntax react-hooks

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

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

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

}
Run Code Online (Sandbox Code Playgroud)

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

let newListCollapsed = [...listCollapsed];
Run Code Online (Sandbox Code Playgroud)

使它工作。我想知道对此的解释是什么。

T.J*_*der 7

你的第一个版本通过直接修改state打破了一个主要的 React 规则(更多关于这部分文档的内容)。线

let newListCollapsed = listCollapsed;
Run Code Online (Sandbox Code Playgroud)

只是 makenewListCollapsed并且listCollapsed两者都引用同一个数组(用作状态的数组),它不会复制数组。当你这样做时,你最终会得到这个:

状态:Ref5461??????????????????+
                              \ +?????????????+ 
listCollapsed:Ref5461??????????+????>| (数组) |
                              / +?????????????+ 
newListCollapsed:Ref5461?????+ | 0: 假 |
                                     | 1:假|
                                     | ... |
                                     +?????????????+

所以

setListCollapse(newListCollapsed);
Run Code Online (Sandbox Code Playgroud)

什么都不做,因为这设置了状态已经包含的相同数组。React 没有看到任何变化。

但是这一行:

let newListCollapsed = [...listCollapsed];
Run Code Online (Sandbox Code Playgroud)

将数组复制到一个新数组中(使用展开表示法将其条目展开到由[]文字创建的新数组中),因此您有:

状态:Ref5461??????????????????+
                              \ +?????????????+ 
listCollapsed:Ref5461??????????+????>| (数组) |
                                     +?????????????+ 
                                     | 0: 假 |
                                     | 1:假|
                                     | ... |
                                     +?????????????+

                                     +?????????????+ 
newListCollapsed:Ref8465????????????>| (数组) |
                                     +?????????????+ 
                                     | 0: 假 |
                                     | 1:假|
                                     | ... |
                                     +?????????????+

因此,当您调用 时setListCollapse(newListCollapsed);,情况就不一样了,并且会发生更改。这是正确的做法。

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