【问题标题】:Why does setState([...arr]) cause a rerender but setState(arr) does not?为什么 setState([...arr]) 会导致重新渲染而 setState(arr) 不会?
【发布时间】:2020-10-12 13:58:50
【问题描述】:

这些不应该做同样的事情吗?第一个代码 sn -p 导致我的组件重新渲染

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 使用浅层对象相等来区分。

标签: reactjs react-hooks react-context


【解决方案1】:

React 只会在组件的状态(或上下文)至少发生变化时重新渲染组件。如果所有之前的状态值都是 === 到新的状态,React 根本不会调用函数组件,而只是继续使用上次渲染的内容。

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

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

【讨论】:

    【解决方案2】:

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

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

    为了更好地理解,你应该阅读这个thread

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 1970-01-01
      • 2019-03-12
      • 1970-01-01
      • 2016-10-20
      • 2019-01-24
      • 2021-12-27
      相关资源
      最近更新 更多