如果您将状态值分配给另一个变量然后更改状态,React 不会触发重新渲染

问题描述

由于缺乏知识和经验,我偶然发现了一种奇怪的行为。 我有一个在另一个内部调用的组件,如下所示:

            <CustomSelectionButtons
              values={roleTypes}
              label="Roles:"
              onSelect={setUserRoles}
              selected={roles}
            />

roles一个状态变量,通过 onSelect 方法 (setUserRoles) 设置。 这是:

  const setUserRoles = (button: AccountsAndRolesUnion) => {
   const updatedRoles: AccountsAndRolesUnion[] = roles; //this is the state variable.

   /* doing something with the local **updatedRoles** array */

   setRoles(updatedRoles);
  };

如果我使用这样的代码,在 setRoles 钩子调用后组件不会重新渲染。 但是,如果我使用roles.slice() 分配局部变量,则一切都按预期工作,组件将重新渲染。 所以,这是有效的:

const setUserRoles = (button: AccountsAndRolesUnion) => {
  const updatedRoles: AccountsAndRolesUnion[] = roles.slice(); //slicing the state variable.

  /* doing something with the local **updatedRoles** array */

  setRoles(updatedRoles);
};

有人可以解释为什么会发生这种情况吗?

解决方法

发生这种情况是因为 const updatedRoles=roles 在内存中为完全相同的对象创建了另一个名称,因此您对 updatedRoles 所做的一切都反映在 roles 中,换句话说,您改变了状态。 roles.slice() 另一方面创建一个新的独立对象。当您将这个新对象传递给 setState 时,React 可以看到差异并触发重新渲染,但是当您将它传递给另一个名称 roles 时,React 认为不需要做任何事情,因为 { {1}} 和 updatedRoles 是一回事。

,

在您的第一个示例中,您使用相同的数组实例来更新状态。 React 只检查浅等式。它不是迭代项目。 .slice() 创建一个新数组。 如果您的状态是数组,请始终创建一个新数组。

,

Slice 创建原始数组的浅拷贝,这意味着它返回的对象与 roles 本身不同,即使其内容可能相同。

当你执行 setRoles(roles) 时,你实际上是在内存中发送完全相同的对象,当 React 在决定是否重新渲染之前比较 props 时,它没有检测到任何差异。然而,当你执行 setRoles(roles.slice()) 时,你在内存中传递了一个不同的变量,所以 React 认为 props 和重新渲染发生了变化。