Javascript 在React中调用生成器的次数超出预期
我发现一个行为,生成器似乎被调用了两次 下面是一个简单的代码,它从生成器获取一个数字并将其输出到控制台。 它期望0和1输出到控制台,但实际上它输出0和2Javascript 在React中调用生成器的次数超出预期,javascript,reactjs,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() { cons
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;
从“react”导入{useState,useffect};
函数*计数器(){
设val=0;
而(true)产生val++;
}
常数计数=计数器();
函数App(){
log(“呈现:count=,count.next().value”);
const[hoge,setHoge]=useState(“第一”);
console.log(“呈现:”,hoge);
使用效果(()=>setHoge(“第二”),[setHoge]);
返回{hoge};
}
导出默认应用程序;
演示:
不仅对useffect
,我还发现了与setInterval
相同的行为。此外,如果我们删除,控制台将按预期输出0和1
你知道为什么会发生这种行为吗?根据
严格模式无法自动检测副作用,但它可以通过使副作用更具确定性来帮助您发现副作用。这是通过故意双重调用以下函数来实现的:
- 类组件构造函数、呈现和shouldComponentUpdate方法
- 类组件静态getDerivedStateFromProps方法
- 功能组件体
- 状态更新程序函数(setState的第一个参数)
- 传递给useState、UseMoom或useReducer的函数
App
函数体将被调用两次,然后在设置新状态时,App
函数体将被调用两次。按照这种逻辑,您应该已经看到了4个以上的日志,即总共8个
以下是出现以下异常的地方:-
从React 17开始,React自动修改控制台
方法(如console.log())在第二次调用
生命周期功能。但是,它可能会导致不希望的行为
在某些情况下,可以使用变通方法
要真正可视化所有8个日志,您只需在顶层执行let log=console.log
,并将console.log
的用法替换为log
,您将看到实际发生的情况
简单地说,不要将这种行为放在功能体中,因为这是严格模式产生的副作用
下面是一个分叉代码沙盒,可以看到:-
存在用于精确检测代码中的反模式操作(渲染函数中的副作用)
此模式故意执行组件的生命周期方法两次(在您的情况下,它是一个功能组件,因此功能执行两次),同时吞下控制台.log
这就是为什么在控制台中没有任何日志的情况下观察生成器增量。为什么将
setHoge
放在useffect
的依赖项数组中?应该是hoge
这不会导致无限的更新,因为每次更新hoge时,useffect都会更新hoge?不,这不会导致无限的更新useffect
检查状态变量而不是状态更新程序函数(setHoge
)。感谢您的详细解释!我现在明白了原因:严格模式是故意读取应用程序两次以检测副作用。这很有趣。副作用是由计数器作为生成器的实现引起的。我没有注意到这一点,尽管现在已经很明显了。非常感谢你!