javascript - 生成器在 React 中的调用次数超出预期
问题描述
我发现生成器似乎被调用了两次的行为。
下面是一个简单的代码,它从生成器中获取一个数字并将其输出到控制台。它期望 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
. 此外,如果我们删除 <React.strict>,控制台会按预期输出 0 和 1。
您知道为什么会发生这种行为吗?
解决方案
根据文档,
严格模式不能自动为您检测副作用,但它可以通过使它们更具确定性来帮助您发现它们。这是通过有意双重调用以下函数来完成的:
- 类组件构造函数、render 和 shouldComponentUpdate 方法
- 类组件静态 getDerivedStateFromProps 方法
- 功能组件体
- 状态更新函数(setState 的第一个参数)
- 传递给 useState、useMemo 或 useReducer 的函数
函数组件体被调用两次是您的问题的原因。这意味着在初始挂载时,App
函数体将被调用两次,然后在设置新状态时,App
函数体将被调用两次。按照这个逻辑,您应该已经看到了另外 4 个日志,即总共 8 个。
这是以下异常出现的地方:-
从 React 17 开始,React 会自动修改 console.log() 等控制台方法,以在对生命周期函数的第二次调用中静默日志。但是,在某些可以使用变通方法的情况下,它可能会导致不良行为。
要实际可视化所有 8 个日志,您可以let log = console.log
在顶层执行并替换console.log
by 的使用log
,您将看到实际发生的情况。
简单地说,不要将这样的行为放在函数体中,因为这是严格模式应运而生的副作用。
这是一个分叉的代码框,可以看到:-
推荐阅读
- javascript - 如何从本地存储中删除搜索栏过去的搜索?
- c++ - 是否可以在编译时强制两个派生类总是为覆盖函数返回不同的值?
- spring - 覆盖 KafkaAutoConfiguration 时出错
- bash - 用于 Windows 的 ubuntu 上的 Mosquitto mqtt
- c# - FluentValidation 使用 DB 检查重复值
- python - 循环遍历 Numpy ndarray 的所有样本
- ios - Xcode 函数中数组的 EXC_BAD_ACCESS
- powershell - 为什么`[SomeType] | Get-Member -Static 返回“SomeType”的静态成员而不是“System.RuntimeType”的静态成员?
- php - 使用 PHPMailer 形成表单
- angular - Angular:创建类对象并提供服务