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

React does not trigger rerender if you assign state value to another variable and then change the state

由于我缺乏知识和经验,我偶然发现了一个奇怪的行为。 我有一个在另一个内部调用的组件,看起来像这样:

            <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 认为不需要做任何事情,因为 updatedRolesroles 是一回事。

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

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

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