You need to enable JavaScript to run this app. 为何React中放在useEffect外的SideEffect执行次数会翻倍?
优惠活动
大模型
产品
解决方案
定价
更多

为何React中放在useEffect外的SideEffect执行次数会翻倍?

问题原因解析

这个现象是React 18+ 开发环境下严格模式(<StrictMode>)的刻意设计,结合两段代码的执行阶段差异导致的:

1. 两段代码的执行阶段差异

  • 写在useEffect回调内的代码:属于React约定的提交阶段副作用,只会在DOM更新完成后执行,不属于渲染函数本身的逻辑。
  • 写在组件顶层(useEffect外)的代码:属于渲染阶段逻辑,组件每触发一次渲染流程,这段代码就会随着组件函数的调用直接执行。

2. 严格模式的双调用规则

React 18及以上版本,官方脚手架(CRA、Vite等)默认会在项目根组件外层包裹<React.StrictMode>,开发环境下会做两个特殊处理,用来提前排查不纯的渲染逻辑导致的bug:

  • 所有渲染流程(包括初始挂载、状态更新触发的重渲染)都会让组件函数被连续调用两次
  • 初始挂载时会模拟「组件卸载 -> 重新挂载」的流程,让useEffect回调执行两次

对应两种场景的表现说明

副作用放在useEffect内符合预期的原因

没有传依赖数组的useEffect,会在每次组件渲染提交完成后执行。严格模式下只有初始挂载时会因为模拟重挂载执行两次effect,后续点击按钮触发重渲染时,effect只会执行一次,所以你感知到的效果是每次点击r自增1,符合预期。

副作用放在useEffect外每次自增2的原因

自增逻辑放在组件函数顶层,属于渲染阶段逻辑,严格模式下每一次渲染都会让组件函数被调用两次,所以每触发一次渲染,r就会被自增2次,也就是你看到的不符合预期的现象。

补充验证

你可以把项目根目录下根组件外层的<React.StrictMode>包裹去掉,重新运行后两个场景的表现就会完全一致,每次点击r都仅自增1。另外这个双调用行为仅存在于开发环境,生产环境打包后会自动关闭,不会影响线上表现。

内容的提问来源于stack exchange,提问作者Mahbubur Rahman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 08:36:06