注:本文是开发个人Electron项目调试useEffect时产生的疑问,再结合以前工作时一直困扰但懒得解决,从而输出的一篇文章。事实证明只有做自己感兴趣的东西时才会想去做的更好...
一、 引言:解读 Electron+React 应用中的双重控制台日志
在开发 Electron 结合 React 的应用程序时,开发者可能会观察到一个现象:控制台(Console)中似乎会打印两次相同的信息。这种重复输出常常引起困惑,让人误以为相关的代码逻辑被执行了两次。这种体验对于初次接触现代 React(尤其是 React 18 及以后版本)行为的开发者来说尤为普遍。
本报告旨在深入解析这一现象背后的具体原因。我们将详细阐释为何会出现这种“双重执行”的表象,区分这是 React 在开发环境下的预期行为,还是开发者代码中实际存在的缺陷。更重要的是,本报告将提供一套清晰、可操作的策略,帮助开发者在 Electron+React 的特定环境下,有效地调试、理解并管理这种行为。
二、 主要原因:理解 React StrictMode
在探究控制台信息重复打印的根源时,最常见的“嫌疑对象”便是 React 的 StrictMode(严格模式)。
定义与目的
React.StrictMode 是 React 提供的一个仅用于开发环境的辅助工具。它的核心价值在于帮助开发者识别应用程序中潜在的问题、不安全的编程实践以及已废弃的 API。需要明确的是,<StrictMode> 组件本身并不会渲染任何可见的用户界面元素;它更像一个“检查器”包裹层,为其后代组件启用额外的检查和警告。
仅限开发环境的行为(关键区别)
最重要的一点是,StrictMode 启用的所有检查和特定行为——包括导致用户观察到双重日志的函数重复调用——仅在开发模式下运行。这意味着这些检查不会影响最终的生产构建版本。这一点对于消除开发者可能存在的关于应用最终性能的顾虑至关重要。
如何启用
在许多现代 React 项目脚手架(如 Create React App, CRA)或类似的模板项目中,StrictMode 通常是默认启用的。开发者可以在项目的入口文件(通常是 src/index.js 或类似文件)中看到主应用组件 <App /> 被 <React.StrictMode> 包裹,其典型语法如下:
JavaScript
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
除了包裹整个应用,StrictMode 也可以用来包裹应用程序组件树的特定部分,以实现更细粒度的检查。
由于 React 18 引入了更积极的 StrictMode 检查机制,并且像 CRA 这样的流行工具默认启用了 React 18 和 StrictMode,这意味着新项目或升级后的项目开发者极有可能在没有显式选择的情况下就遇到这种“双重日志”行为。因此,用户的观察结果并非异常,而是当前 React 开发生态中的标准体验,应将其视为一个需要理解的特性,而非一个需要修复的 bug。
StrictMode 的存在及其演进,实际上反映了 React 团队持续引导开发者采用更具弹性、更能适应未来变化的编程模式的决心,尤其是在处理并发渲染和副作用方面。最初,StrictMode 主要关注识别遗留或不安全的 API。然而,React 18 的更新特别增加了对 Effect 清理逻辑以及组件纯洁性/弹性的检查。这些新增检查与 React 18 中并发特性(如 startTransition)的稳定发布相辅相成。因此,StrictMode 不仅仅是为了捕捉旧错误,更是通过在开发时强制执行更严格的规则,主动地为 React 的架构发展方向(如异步渲染、可中断渲染)准备代码库。
三、 为何在开发中执行两次(这是故意的!)
StrictMode 在开发模式下故意执行某些操作两次,其背后有明确的目的。
A. 双重渲染:检测不纯组件
StrictMode 会有意地在开发环境中调用某些函数两次。这包括函数组件的函数体本身、传递给 useState 或 useReducer 的状态更新函数,以及传递给 useMemo 的函数。
目的: 此举旨在帮助开发者识别“不纯”(impure)的渲染逻辑。在此语境下,“纯洁性”意味着一个组件在给定相同的输入(props 和 state)时,应始终产生相同的输出(JSX 结构和副作用)。
机制: 如果一个函数是纯粹的,那么执行它两次不会产生任何可观察的差异。然而,如果函数是不纯的(例如,它修改了传入的 props、修改了外部变量、或者在没有先克隆的情况下向数组添加元素),那么执行两次很可能会导致明显的不一致或错误,从而暴露其不纯性。
示例: 一个常见的例子是直接修改传入的数组。如果在组件渲染逻辑中直接对一个 prop 数组执行 push 操作,StrictMode 下该组件渲染两次,会导致同一个元素被添加两次。这立刻提示开发者需要先创建数组的副本(例如使用 stories.slice() 或扩展运算符 [...stories])再进行修改,以保持渲染的纯洁性。
B. 双重 useEffect 执行:模拟挂载-卸载-再挂载
自 React 18 起,StrictMode 对 useEffect 的行为有特定处理:在组件首次挂载时,React 会执行一个额外的“设置 + 清理”周期。
执行序列:
- 组件挂载(Mount)。
useEffect的设置(setup)函数运行。useEffect的清理(cleanup)函数立即运行。useEffect的设置(setup)函数再次运行。
目的:
- 验证清理逻辑: 确保
useEffect返回的清理函数能够正确地拆除或清理设置函数所初始化的资源(例如,取消订阅、清除定时器、移除事件监听器)。这有助于捕捉内存泄漏或残留的副作用。 - 确保状态可重用/弹性: 模拟组件被卸载后立即重新挂载的场景,测试组件逻辑在这种条件下的健壮性。这对于像 Fast Refresh(快速刷新)这样的开发功能以及未来可能出现的 Offscreen(离屏)组件等特性非常重要。
示例: 考虑一个在 useEffect 中使用 setInterval 设置定时器,但忘记在清理函数中调用 clearInterval 的情况。在 StrictMode 下,由于设置函数运行了两次而清理函数可能未能正确执行(或在模拟卸载时执行),可能会导致两个定时器同时运行,或者在模拟卸载后留下一个运行中的定时器,使得问题(如计数器速度加倍)变得明显。类似地,如果在 useEffect 中获取数据但没有使用 AbortController 等机制在清理时取消请求,这种模拟卸载再挂载的行为有助于暴露潜在的竞态条件(旧请求的结果覆盖了新请求)或在“已卸载”组件上设置状态的问题。
C. 双重 Callback Ref 执行
简要提及,回调形式的 ref(Callback Refs)也会经历一次额外的设置和清理周期,原因类似:验证其卸载逻辑的正确性。
值得注意的是,这种“挂载-卸载-再挂载”更准确地理解应为一种模拟,而非开发者直觉中认为的组件实例的字面意义上的销毁和重建。组件的状态(state)和引用(refs)在此模拟过程中是被保留的。React 18 的早期文档描述可能引起了混淆,但实际观察和后续澄清表明,useRef 的值在 useEffect 的两次调用之间是持续存在的。如果真的是完全卸载,ref 通常会被重置。官方文档后来也倾向于使用“模拟卸载和重新挂载”或“运行一次额外的设置+清理周期”等措辞。因此,其关键影响在于 Effect 的生命周期行为,而不是组件实例的身份或其非 Effect 状态/引用。理解这一区别对于调试和正确评估某些“修复”手段(如 useRef 标志)至关重要。
这种在开发环境中进行的严格测试,其深层目的是使组件对现实世界中的复杂场景(如用户快速切换页面或未来 React 可能采用的新渲染策略)更具鲁棒性,从而有效提升组件的整体质量标准。React 团队明确将这种模拟与发现那些在用户快速导航(例如 A -> B -> A)时可能出现的 bug 联系起来。同时,StrictMode 也被认为是帮助应用为异步/并发渲染做好准备的工具。通过强制 Effect 处理立即清理和重新设置,React 确保了组件不依赖于单一、不间断的挂载生命周期。这无形中使得组件适应性更强,在更动态的渲染环境中(无论是用户驱动还是框架驱动)更不容易出现状态不一致或资源泄漏的问题。
四、 这是代码中的 Bug 吗?(可能不是,但需要检查……)
澄清预期行为与实际 Bug
需要再次强调,由于 StrictMode 的存在,在开发环境中看到日志或函数执行两次是预期行为。
关键问题在于:这种双重执行是否在应用程序中引发了不正确的行为?
- 如果一个
useEffect没有正确的清理逻辑,导致重复的数据获取并错误地更新了状态(例如,将相同的数据追加了两次),那么这是一个由StrictMode暴露出来的 Bug。 - 如果一个渲染函数依赖于外部可变状态,并且在第二次渲染时产生了错误的 UI,那么这是一个由
StrictMode暴露出来的 Bug。 - 如果唯一的症状只是在控制台看到
console.log打印了两次,但应用程序的状态和 UI 保持正确,那么这很可能不是代码中的 Bug,而仅仅是开发环境检查过程的一个可见产物。
组件纯洁性与 Effect 幂等性的重要性
这与第三部分讨论的概念紧密相连。编写代码时应遵循纯函数原则(对于渲染逻辑)并确保 Effect 是幂等的(即,执行多次与执行一次具有相同的最终效果,通常通过正确的清理逻辑实现),这是让 StrictMode 的检查“静默”通过的关键。
开发环境 (StrictMode) vs. 生产环境行为总结表
为了更清晰地对比,下表总结了关键行为在不同环境下的表现:
| 特性 | 开发环境行为 (StrictMode) | 生产环境行为 | 开发检查目的 |
|---|---|---|---|
| 组件渲染 (纯函数) | 调用两次。无功能性影响。 | 调用一次。 | 检测不纯性 |
| 组件渲染 (不纯函数) | 调用两次。可能导致错误的 UI/状态。 | 调用一次。不纯性仍可能在后续引发问题。 | 检测不纯性 |
useEffect 挂载 (带清理) | 设置 -> 清理 -> 设置。日志打印两次,但功能正常。 | 挂载时设置运行一次。 | 验证清理逻辑/弹性 |
useEffect 挂载 (无/错清理) | 设置 -> 清理 -> 设置。可能导致内存泄漏、竞态条件、状态错误。暴露潜在问题。 | 挂载时设置运行一次。卸载或后续操作时可能发生泄漏/Bug。 | 暴露清理逻辑问题 |
useEffect 更新 (带清理) | (依赖项变化时) 清理 -> 设置。 | (依赖项变化时) 清理 -> 设置。 | (同生产环境) |
useEffect 卸载 (带清理) | 清理运行一次 (在模拟卸载时也运行过一次)。 | 清理运行一次。 | (同生产环境,但已验证) |
此表直接对比了开发者在开发时所见(受 StrictMode 影响)与应用在生产环境的实际运行情况(用户最终体验)。它有助于开发者判断遇到的问题是 StrictMode 的正常表现,还是指示了需要修复的真正代码缺陷。同时,它将观察到的行为与其背后的检查目的联系起来,指导开发者是需要修复代码(如果不纯或清理有问题),还是仅仅理解开发环境的特殊性(如果代码本身是健壮的)。
在这种背景下,“Bug”的定义也发生了微妙的变化。问题本身不在于代码执行了两次,而在于代码的脆弱性被这种双重执行所暴露。StrictMode 有意地重复执行某些操作。编写良好、具有弹性的代码应该能够处理这种情况而不会产生错误的副作用。如果双重执行破坏了应用程序的逻辑或状态,那就意味着代码本身就不够健壮(例如,缺乏纯洁性、没有正确的清理)。因此,“Bug”并非 React 的行为,而是开发者代码中预先存在的、被 StrictMode 成功高亮出来的弱点。
更进一步看,学会编写能够在 StrictMode 下良好运行的代码,本身就会引导开发者形成更健壮、可预测和可维护的 React 应用开发习惯,即使不考虑它直接捕捉到的 Bug。StrictMode 强制开发者遵守纯函数原则和 Effect 清理规则。纯函数更容易测试和理解。正确的 Effect 清理可以防止资源泄漏和状态不一致。能够适应挂载/卸载周期的组件,在面对未来 React 特性或复杂 UI 流程时,也不太可能出现问题。因此,与其抵触 StrictMode 的约束,不如拥抱它们,将其视为培养更高质量代码开发习惯的契机。
五、 调试与验证行为
要确认重复日志是否确实由 StrictMode 引起,并进一步排查可能暴露的问题,可以使用以下工具和方法。
A. 使用 React DevTools(必备工具)
安装: 首先需要安装 React 开发者工具。它可以作为浏览器扩展(适用于 Chrome、Firefox 等)安装,也可以作为独立的 npm 包安装。对于 React Native 应用,它已集成在 React Native DevTools 中。
识别 StrictMode 日志: 安装并打开浏览器开发者工具后,切换到 "Components" 或 "Profiler" 标签页。一个重要的视觉线索是,React DevTools 通常会将由 StrictMode 双重调用产生的第二组 console.log 输出渲染得颜色稍浅,或者提供设置项来完全隐藏它们。这可以立即提供视觉确认,表明重复日志很可能源于 StrictMode。隐藏第二组日志的设置通常位于:Components 标签页 -> 右上角齿轮图标(设置)-> Debugging 标签页 -> 勾选 "Hide logs during second render in Strict Mode"。
高亮组件更新: 在 React DevTools 的设置中(Components 标签页 -> 右上角齿轮图标 -> General 标签页),可以启用 "Highlight updates when components render"(当组件渲染时高亮更新)选项。启用后,每当组件重新渲染时,其在页面上的边界会短暂闪烁高亮。这有助于将控制台日志与实际的组件渲染活动关联起来,直观地看到哪些组件正在(可能重复地)渲染。
使用 Profiler(性能分析器):
-
访问: 切换到 React DevTools 的 "Profiler" 标签页。
-
录制: 点击录制按钮(通常是一个圆形的开始按钮),然后与应用程序交互,触发那些导致双重日志的状态变化或 Effect 执行。完成交互后,点击停止录制。
-
解读:
- Profiler 会展示交互期间发生的渲染提交(Commits)。火焰图(Flamegraph)或排序图(Ranked chart)会显示每个组件在每次提交中的渲染耗时。
- 关键在于: 在 Profiler 的设置中(Profiler 标签页 -> 右上角齿轮图标),务必勾选 "Record why each component rendered while profiling"(记录每个组件渲染的原因)。启用后,选择某次提交(commit)和某个组件,Profiler 会明确告知该组件此次渲染的原因,例如 "Props changed"(Props 变化)、"Hooks changed"(Hooks 变化,通常指 state 或 context 变化)、"Parent component rendered"(父组件渲染导致)等。这对于精确诊断为何一个组件(及其包含的日志或 Effect)会运行至关重要。
B. 检查代码设置
引导开发者检查项目的入口文件(如 src/index.js),确认 <React.StrictMode> 是否包裹了 <App /> 或组件树的其他部分。这是确认 StrictMode 是否为主要原因的最直接方式。
有效的调试过程在于利用专门的工具,将观察到的症状(重复日志)与潜在的原因(由 StrictMode 引发的重复渲染/Effect 执行)联系起来。用户看到了重复日志。StrictMode 会导致重复渲染和 Effect 执行(如第三部分所述)。React DevTools 提供了专门的功能来可视化渲染("Highlight updates")并解释其发生的原因("Profiler - why rendered")。因此,使用这些工具可以让开发者直接观察到 StrictMode 机制的作用,并确认是它导致了日志重复,而不是其他无关的 Bug。
掌握 React DevTools,特别是 Profiler 的使用,标志着调试方式的转变——从基于日志的猜测,转向基于数据的组件行为和性能分析。简单的 console.log 只能显示代码是否运行,但通常不能揭示其运行的原因或效率如何。Profiler 则提供了定量数据(渲染时间、提交阶段)和定性数据(渲染原因)。这使得开发者能够从“日志打印了两次”的表面现象,深入到“组件 X 因为 Hook Y 变化而渲染,耗时 Z 毫秒”的层面,从而实现有针对性的优化和调试。这代表了一种更成熟、更有效的理解和改进 React 应用程序的方法。
六、 管理双重执行的策略
面对 StrictMode 带来的双重执行,有多种应对策略,但它们并非等效。
A. 编写弹性代码(推荐的最佳实践)
这是最根本且推荐的方法:编写能够自然应对 StrictMode 检查的代码。
-
确保组件纯洁性: 强调避免在组件函数体或渲染逻辑中直接执行副作用。例如,在修改数据结构(如数组或对象)之前,先进行克隆(使用
slice()、扩展运算符...或Object.assign()等。纯组件自然能够处理双重渲染而不会产生问题。 -
掌握
useEffect清理函数: 对于useEffect来说,这是最关键的部分。-
语法: 从
useEffect的回调函数中return一个函数,这个返回的函数就是清理函数。 -
具体示例:
- 数据获取 (Fetching Data): 使用
AbortController在清理时取消网络请求。这可以防止竞态条件(旧请求覆盖新数据)和在组件卸载(或模拟卸载)后尝试更新状态。
JavaScript
useEffect(() => { const controller = new AbortController(); const signal = controller.signal; fetch('/api/data', { signal }) .then(response => response.json()) .then(data => { /*... set state... */ }) .catch(error => { if (error.name === 'AbortError') { console.log('Fetch aborted'); } else { // Handle other errors } }); // Cleanup function return () => { controller.abort(); }; },);11
- 定时器 (Timers): 在清理函数中使用
clearInterval(intervalId)或clearTimeout(timeoutId)来清除定时器。 - 订阅 (Subscriptions): 如 WebSocket 连接或通过
addEventListener添加的事件监听器,应在清理函数中取消订阅或移除监听器。
- 数据获取 (Fetching Data): 使用
-
必要性解释:
StrictMode下,清理函数会在模拟卸载时立即执行,这正好测试了清理逻辑是否正确和有效。
-
B. 利用数据获取库
可以考虑使用像 React Query (TanStack Query) 或 SWR 这样的库来管理数据获取。
这些库通常内置了请求去重(deduplication)和缓存机制。这意味着,即使调用这些库的 useEffect Hook 执行了两次,库本身可能只会发出一次实际的网络请求,从而在现象上“掩盖”了双重 fetch 的问题 11。React 团队也常常推荐使用这类库来处理数据获取。
C. 条件化 Effect 执行(极其谨慎使用)
一个常见的、用于让 Effect 只运行一次的模式是使用 useRef 来跟踪 Effect 是否已经运行过:
JavaScript
import React, { useEffect, useRef } from 'react';
function MyComponent() {
const hasRun = useRef(false);
useEffect(() => {
// 检查标志位,仅在第一次运行时执行
if (!hasRun.current) {
hasRun.current = true;
console.log("Effect logic runs only once");
//... 执行只需要运行一次的逻辑...
}
// 注意:即使使用了这个模式,如果需要清理,清理函数仍然应该存在
// return () => { /*... cleanup logic... */ };
},); // 空依赖数组确保只在挂载时运行(或尝试运行)
//...
}
4
强烈警告: 必须强调,这种模式通常是不被推荐的,原因如下:
- 它绕过了
StrictMode设计用来执行的检查。 - 它可能掩盖了清理逻辑或组件弹性方面的潜在 Bug,这些 Bug 在生产环境中或其他条件下仍可能出现。
- 它增加了代码的复杂度,引入了额外的模板代码。
尽管一些资料(包括一些 Stack Overflow 的回答或评论)将其展示为一种“解决方案”,但应将其视为最后的手段或临时变通,而非最佳实践。
D. 禁用 StrictMode(强烈不推荐)
可以通过移除 index.js 中包裹 <App /> 的 <React.StrictMode> 标签来禁用严格模式。对于 Next.js 项目,可以在 next.config.js 中设置 reactStrictMode: false。
强烈建议不要这样做: 禁用 StrictMode 的弊端非常明显:
- 失去了
StrictMode提供的所有有价值的检查和警告。 - 与副作用、清理逻辑或废弃 API 相关的潜在 Bug 可能直到生产环境才被发现。
- 阻碍了编写更健壮、更能适应未来 React 发展的代码的过程。这相当于为了短期的便利牺牲了长期的代码健康。
这些解决方案形成了一个层级结构,反映出一种倾向:优先解决问题的根源(代码的弹性),而不是仅仅管理症状(双重执行)。最受推崇的方法是编写本身就能通过 StrictMode 检查的弹性代码 (A)。使用库 (B) 则通过工具抽象了部分复杂性,提供了弹性。而像 useRef hack (C) 或禁用 StrictMode (D) 这样的变通方法,则主动规避了检查,虽然解决了眼前的症状,但可能隐藏了更深层次的问题。这种优先级排序符合软件工程中倾向于稳健设计而非表面修复的原则。
围绕 StrictMode 双重执行(尤其是 useEffect)的讨论,也凸显了 React 团队希望强制推行适应未来架构(并发、弹性)的模式,与这些强制机制对开发者体验造成的影响之间的张力。React 18 中 useEffect 的行为变化引起了广泛的困惑甚至一些挫败感。React 团队辩护称这是发现 Bug 和确保弹性的必要手段。然而,开发者有时觉得这些检查过于严苛或变通方法太麻烦,导致他们考虑禁用或使用 hack。这反映了框架演进中一个典型的困境:如何在强制推行符合框架长远目标的“正确”模式与保证开发者即时生产力和直观理解之间取得平衡。
七、 考虑 Electron 特定的边缘情况
需要提醒的是,应用程序运行在 Electron 环境中,这个环境本身就包含多个层次:主进程(Main Process)、渲染进程(Renderer Process)、预加载脚本(Preload Scripts)以及构建工具链。
首先排除 StrictMode: 必须强调,绝大多数 React 应用(无论是否在 Electron 中)出现的“双重执行”症状都源于 StrictMode。只有在确认 StrictMode 不是原因,或者在解决了 StrictMode 相关问题后行为仍然存在时,才应调查以下这些可能性。
潜在的 Electron 相关原因(可能性较低):
- 重复模块加载 (Duplicate Module Loading): 构建配置可能意外地将 React 或 ReactDOM 打包了两次,这可能导致难以预料的行为。可以通过检查
npm ls react或使用开发者工具追踪模块导入路径来排查。 - 构建工具/热模块替换 (HMR) 问题: 有时开发服务器或 HMR 配置可能存在故障,尤其是在像 Electron 模板项目这样的复杂环境中,可能导致更新或日志记录重复。这通常是工具链的 Bug,而非 React 或应用程序代码的问题。
- IPC 配置错误 (IPC Misconfigurations): 虽然不太可能直接导致 React 组件的双重渲染,但主进程和渲染进程之间不当的进程间通信(IPC)设置,如果处理不慎,理论上可能导致动作重复执行(这是一个概念上的联系,现有资料中缺乏直接证据表明它会导致 组件内日志 重复)。可以简要参考 Electron 的 IPC 文档。
- 多个日志记录器 (Multiple Loggers): 如果同时监控 Electron 主进程的日志和渲染进程的控制台,或者存在重复的自定义日志设置,也可能造成混淆(虽然对于组件内部的
console.log来说可能性较小,但与整体控制台噪音有关)。
Electron 环境增加了额外的复杂性层次(构建过程、多个 JavaScript 上下文),这些层次理论上可能模拟出类似的症状,但它们的机制与 React 有意的 StrictMode 行为是不同的。Electron 应用涉及为主进程、渲染进程和预加载脚本分别进行打包。这里的配置错误可能导致诸如模块重复或 HMR 故障之类的问题。这些属于构建时或开发服务器层面的问题。而 React StrictMode 是 React 框架内部的一种运行时检查机制。因此,尽管症状(例如,双重日志)可能相似,其根本原因和调试方法将完全不同(前者需要检查 webpack/vite 配置,后者需要检查 React 组件逻辑)。
在 Electron 中进行调试,需要意识到问题可能出现在多个层面:Web 框架层(React)、构建工具层(Webpack/Vite)以及 Electron 平台本身(IPC、进程模型)。用户的查询是关于 Electron 环境下的 React 行为。主要原因被确定为 React 的 StrictMode。此外,Electron 本身就涉及多进程和 IPC 。因此,一个全面的 Electron+React 应用调试策略必须考虑到来自任何这些层面的潜在故障,即使对于当前这个特定症状,框架层(React)是最可能的起点。
八、 结论:拥抱稳健的开发实践
总结来看,在 Electron+React 应用开发过程中观察到的控制台信息重复打印现象,几乎可以肯定是由 React.StrictMode 在开发环境下的预期行为所致。它并非通常意义上的 Bug,而是一个旨在帮助开发者发现潜在问题的特性。
最有效且推荐的“解决方案”,并非禁用这些检查或使用规避手段,而是编写本身就具有弹性的组件和 Effect——确保渲染逻辑的纯洁性,并为 useEffect 实现彻底、正确的清理逻辑。这不仅能让 StrictMode 的检查顺利通过,也符合 React 的发展方向,最终会带来更优质、更可维护的代码。
尽管 StrictMode 的行为初看可能令人惊讶,但鼓励开发者将其视为构建高质量、健壮的 Electron+React 应用程序的宝贵盟友。理解并适应 StrictMode 的要求,是迈向精通现代 React 开发的重要一步。
最后也欢迎大家在评论区给出自己的意见,如果觉得这篇文章有些帮助,不妨给个赞,这也是作者更新的最大动力,谢谢!