【问题标题】:React useState reruns the component function on no changeReact useState 在没有变化的情况下重新运行组件功能
【发布时间】:2022-01-09 14:38:41
【问题描述】:

在这个非常简单的演示中

import { useState } from 'react';
 
function App() {
  const [check, setCheck] = useState(false);
  console.log('App component Init');
  return (
    <div>
      <h2>Let's get started! </h2>
      <button
        onClick={() => {
          setCheck(true);
        }}
      >
        ClickMe
      </button>
    </div>
  );
}
 
export default App;
 

我得到一个登录应用程序初始化,

在第一次单击时(状态从 false 变为 true),我按预期得到另一个日志。

但是在第二次点击时我也得到了一个日志,尽管状态保持不变。(有趣的是,ReactDevTools 不会像重新渲染时那样在组件周围产生高亮效果)

对于随后的每一次点击都不会显示日志。

为什么会出现这个额外的日志。 这是一个 stackblitz 演示: https://stackblitz.com/edit/react-ts-wvaymj?file=index.tsx 提前致谢

【问题讨论】:

  • 检查状态为真,我认为它始终为真。所以视图不渲染。你可以试试 setCheck(!check);
  • 停止这些额外的渲染使用“useCallback”。 useCallback 将返回回调的记忆版本,只有在依赖项之一发生更改时才会更改,因此如果相同的值传递给函数,它将停止额外渲染
  • @Sanoodia useCallback 在这里完全没用,因为没有依赖组件会接收该回调作为道具。
  • 我包含了一个 stackblitz 演示 stackblitz.com/edit/react-ts-wvaymj?file=index.tsx 按下按钮并查看日志我只是想看看 useState 是如何工作的而不是创建一些东西。

标签: reactjs react-hooks use-state


【解决方案1】:

给定

我得到一个登录应用程序初始化,

在第一次点击时(状态从假变为真)我得到另一个 按预期记录。

但是在第二次点击时我也得到了一个日志,虽然状态仍然存在 一样。(有趣的是 ReactDevTools 不会产生高光 组件周围的效果,就像重新渲染时一样)

对于随后的每一次点击都不会显示日志。

你的问题是

为什么会出现这个额外的日志?

检查useState Bailing Out of a State Update 部分(强调我的):

如果您将状态挂钩更新为与当前状态相同的值, React 将在不渲染子元素或触发效果的情况下退出。 (React 使用 Object.is comparison algorithm。)

请注意,React 可能仍需要再次渲染该特定组件 在纾困之前。 这不应该是一个问题,因为 React 不会 不必要地“深入”到树中。如果你做的很贵 渲染时计算,你可以使用useMemo优化它们。

您的问题的答案基本上是,“这就是 React 和 useState 挂钩的工作方式。”我猜第二个额外的渲染是检查没有子组件需要更新,一旦确认,相同值的所有进一步状态更新都将被忽略。

【讨论】:

  • 伟大而清晰的答案!
【解决方案2】:

如果你控制台日志检查你可以看到...

您将获得check 的第一次点击是true -> 检查状态变化从 false (init) => true (click) => state change => view change => log expected.

第二次点击 => 检查状态为真(从第一次点击开始) => 真 => 状态不变 => 视图不渲染。

所以。你可以试试

 setCheck(!check);

【讨论】:

  • 我包含了一个 stackblitz 演示 stackblitz.com/edit/react-ts-wvaymj?file=index.tsx 按下按钮并查看日志我只是想看看 useState 是如何工作的而不是创建一些东西。
  • useState 工作但没有任何变化。
  • 在基于先前状态改变状态时使用 prevState 回调。所以不要使用 setCheck(!check),而是使用 setCheck((prevState) => !prevState)。这将确保您获得“最新的先前”状态。
猜你喜欢
  • 2021-10-11
  • 2020-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-10
  • 2021-11-14
  • 2022-07-08
  • 1970-01-01
相关资源
最近更新 更多