我发现生成器似乎被调用了两次的行为。
下面是一个简单的代码,它从生成器中获取一个数字并将其输出到控制台。 它期望将 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
相同的行为。此外,如果我们删除
您知道为什么会发生这种行为吗?
最佳答案
根据 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来看到这个:-
关于javascript - 生成器在 React 中的调用次数超过预期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67709551/