javascript - 生成器在 React 中的调用次数超过预期

标签 javascript reactjs

我发现生成器似乎被调用了两次的行为。

下面是一个简单的代码,它从生成器中获取一个数字并将其输出到控制台。 它期望将 0 和 1 输出到控制台,但实际上它输出 0 和 2。

import { useState, useEffect } from "react";
 
function* counter() {
  let val = 0;
  while (true) yield val++;
}
const count = counter();

function App() {
  console.log("rendered: count = ", count.next().value);
  const [hoge, setHoge] = useState("first");
  console.log("rendered:", hoge);

  useEffect(() => setHoge("second"), [setHoge]);
  return <div>{hoge}</div>;
}

export default App;

演示: https://codesandbox.io/s/friendly-http-g84cp?file=/src/App.tsx

不仅useEffect,我还发现了与setInterval 相同的行为。此外,如果我们删除 ,控制台会按预期输出 0 和 1。

您知道为什么会发生这种行为吗?

最佳答案

根据 docs ,

严格模式无法自动为您检测副作用,但它可以通过使副作用更具确定性来帮助您发现它们。这是通过有意地重复调用以下函数来完成的:

  • 类组件构造函数、render 和 shouldComponentUpdate 方法
  • 类组件静态getDerivedStateFromProps方法
  • 函数组件体
  • 状态更新函数(setState 的第一个参数)
  • 传递给 useState、useMemo 或 useReducer 的函数

Function component bodies 被调用两次是导致问题的原因。这意味着在初始挂载时,App 函数体将被调用两次,然后在设置新状态时再次调用,App 函数体将被调用两次。按照这个逻辑,您应该已经看到了 4 个日志,即总共 8 个。

这是以下异常的来源:-

Starting with React 17, React automatically modifies the console methods like console.log() to silence the logs in the second call to lifecycle functions. However, it may cause undesired behavior in certain cases where a workaround can be used.

要实际可视化所有 8 个日志,您只需在顶层执行 let log = console.log 并将 console.log 的用法替换为 登录,您将看到实际发生的情况。

简单地说,不要将这样的行为放在函数体中,因为它是严格模式的副作用成为现实。

这是一个 fork 的codesandbox来看到这个:-

Edit dreamy-aryabhata-ddzyz

关于javascript - 生成器在 React 中的调用次数超过预期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67709551/

相关文章:

javascript - 如何在考虑瓦片高度的情况下计算等轴测世界中鼠标下方瓦片的索引

javascript - 如何在单击按钮时创建网格?

javascript - 在 IOS 设备上暂停 (html5) youtube 视频

javascript - 登录后如何在 React Navigation 中重定向

javascript - axios删除方法在 react 中不起作用

ios - 如何在 React Native 中使用现有的 Swift 应用程序?

javascript - 在基于 promise 的循环中避免递归堆栈溢出?

javascript - 为什么解构的工作方式不同于 Javascript (ES6) 中的经典赋值?

javascript - 我如何在 React.js 中返回从 axios 带来的数据?

html - react 最佳实践 : logic vs functions in JSX