为什么 setState([...arr]) 会导致重新渲染,而 setState(arr) 不会?

Why does setState([...arr]) cause a rerender but setState(arr) does not?

这些不应该做同样的事情吗?第一个代码片段导致我的组件重新呈现

const context = React.useContext(myContext);
const { arr, setArr } = context;

const addItem = (item) => {
    arr[0].subArr.push(item);
    setArr([...arr]);
}

但这不

const context = React.useContext(myContext);
const { arr, setArr } = context;

const addItem = (item) => {
    arr[0].subArr.push(item);
    setArr(arr);
}

setArr 只是从 React.useState() 中提取的,我没有构建自定义功能

React 只会 re-render 一个组件,如果它的状态(或上下文)中的至少一个项目发生变化。如果所有以前的状态值都是 === 到新状态,React 根本不会调用功能组件,只是继续使用上次渲染的内容。

这是您永远不应在 React 中改变状态的原因之一 - 它可能导致意外或不可预测的行为。

在您的情况下,当您执行 setArr(arr) 时,由于 arr 与当前处于状态上下文中的数组完全相同,因此 React 会跳过 re-rendering,因为新状态是 ===到旧状态。只有通过创建一个 new 数组,而不是 === 当前状态才会发生 re-render。

要理解这一点,你已经理解了数组在 JS 中是如何被处理的。用简单的英语来说,当你创建一个数组时,JS 知道数组引用,这是存储数组的内存地址。现在,虽然您正在更改数组中的项目,但它不会更改引用。当 JS 试图找到该数组时,它会在旧位置找到它。因此,从 JS 的角度来看,尽管项目发生了变化,但数组并没有改变。我们知道除非状态发生变化,否则 React 不会 re-render。所以,当你写 setState(arr) 时,react 发现数组引用没有改变,因此没有 re-render.

另一方面,当您编写 setState([...arr]) 时,我们正在创建一个包含 arr 数组项的新数组。因此,在这种情况下,react 发现数组引用已更改。所以,它 re-renders.

为了更好地理解,您应该阅读这篇文章thread