首页 > 解决方案 > useEffect Hook 示例:导致重新渲染的原因是什么?

问题描述

我试图弄清楚 useEffect 何时导致重新渲染。我对以下示例的结果感到非常惊讶:

https://codesandbox.io/embed/romantic-sun-j5i4m

function useCounter(arr = [1, 2, 3]) {
  const [counter, setCount] = useState(0);
  useEffect(() => {
    for (const i of arr) {
      setCount(i);
      console.log(counter);
    }
  }, [arr]);
}

function App() {
  useCounter();
  console.log("render");
  return <div className="App" />;
}

这个例子的结果如下:

在此处输入图像描述

我不知道为什么:

  1. 该组件仅渲染 3 次(我猜该组件会为每次调用setCount+ 一个初始渲染重新渲染 - 所以 4 次)
  2. 计数器只有两个值 0 和 3:我猜,正如本文所述,每个渲染都会看到自己的状态和道具,因此整个循环将以每个状态作为常数 (1, 2, 3) 运行-->但是为什么状态永远不是 2?

标签: reactjsreact-hooks

解决方案


我将尽我所能解释(或介绍)正在发生的事情。我也在第 7 点和第 10 点做了两个假设。

  1. 应用组件挂载。
  2. useEffect在安装后调用。
  3. useEffect将“保存”初始状态,因此counter无论何时在其中引用时都将为 0。
  4. 循环运行 3 次。每次迭代setCount都被调用以更新计数,并且控制台日志记录根据“存储”版本为 0 的计数器。因此,数字 0 在控制台中记录了 3 次。因为状态已经改变 (0 -> 1, 1 -> 2, 2 -> 3) React 设置像一个标志或其他东西来告诉自己记住重新渲染。
  5. React 在执行期间没有重新渲染任何东西useEffect,而是等到useEffect完成重新渲染。
  6. 完成useEffect后,React 会记住counter在其执行期间的状态已更改,因此它将重新渲染应用程序。
  7. 应用程序重新渲染并useCounter再次调用。注意这里没有参数被传递给useCounter自定义钩子。 假设: 我自己也不知道这一点,但我认为默认参数似乎是再次创建的,或者至少以某种方式让 React 认为它是新的。因此,因为arr被视为新的,useEffect钩子将再次运行。useEffect这是我可以解释第二次跑步的唯一原因。
  8. 在第二次运行期间useEffectcounter的值为 3。因此,控制台日志将按预期将数字 3 记录 3 次。
  9. useEffect第二次运行后,React 发现计数器在执行期间发生了变化(3 -> 1, 1 -> 2, 2 -> 3),因此应用程序将重新渲染,从而导致第三个“渲染”日志。
  10. 假设: 因为从 App 的角度来看,钩子的内部状态useCounter在这次渲染和之前的渲染之间没有改变,它不会执行其中的代码,因此useEffect不会第三次调用。所以应用程序的第一次渲染总是会运行钩子代码。第二次 App 看到 hook 的内部状态counter从 0 变为 3 决定重新运行,第三次 App 看到内部状态是 3 仍然是 3 所以决定不重新运行-运行。这是我能想出的让钩子不再运行的最好理由。您可以在钩子本身中放置一个日志,以查看它实际上不会运行第三次。

这就是我看到的情况,我希望这让它更清楚一点。


推荐阅读