React Strict Mode 下 useEffect 为什么会执行两次? 慕容梓晨 提问于 2026-03-02 17:50:20 阅读 35 框架 我在开发时开启了 React 的 Strict Mode,结果发现 useEffect 里的逻辑执行了两次,明明只渲染了一次组件。这是正常现象吗?会不会影响生产环境? 我试过把依赖数组清空,也试过移除 Strict Mode,确实只有在 Strict Mode 下才会双触发。下面是我的代码: useEffect(() => { console.log('副作用执行了'); // 模拟数据请求或初始化操作 }, []); 我来解答 赞 10 收藏 分享 生成中... 手机扫码查看 复制链接 生成海报 反馈 发表解答 您需要先 登录/注册 才能发表解答 2 条解答 UE丶玉鑫 Lv1 这事儿我之前也踩过,确实挺膈应的。 先说结论:这是 React 18 的正常行为,不是 bug。Strict Mode 在开发环境下会故意让你的组件挂载两次、卸载两次、再挂载,用来检测你的副作用代码是否正确清理。 原理很简单,React 18 引入了一个「开发者辅助」机制:它会在第一次挂载后模拟一次「意外卸载」,然后立刻重新挂载。如果你写在 useEffect 里的代码没有返回 cleanup 函数,或者 cleanup 写得有问题(比如事件监听没移除、定时器没清理、请求没取消),这时候就能暴露出来。 说人话就是:React 在帮你检查「如果用户离开页面,你的副作用会不会留下内存泄漏或者副作用残留」。很多同学写 useEffect 时忘了 return cleanup,或者 cleanup 写错了,这个双挂载机制能帮你提前发现。 至于会不会影响生产环境——不会。生产环境下组件只挂载一次,只有开发环境+Strict Mode 才会这样。 解决方案其实就一条:确保你的 useEffect 里有正确的 cleanup。比如你代码里是模拟请求,那就应该这样写: useEffect(() => { console.log('副作用执行了'); // 你的初始化逻辑 return () => { console.log('清理函数执行了'); // 在这里清理:取消请求、移除监听器、清除定时器等 }; }, []); 如果你确实没有需要清理的东西,也不用硬加 return,但最好加上注释说明为什么不需要清理,方便以后维护的人(可能就是你自己)看得懂。 回复 点赞 2026-03-20 08:27 Air-欣龙 Lv1 这是 React 18 的预期行为,不是 bug,别慌。 Strict Mode 在开发环境下会故意把组件挂载、卸载、再挂载一次,目的是帮你检测副作用是否写得干净。React 官方这么设计是为了让你早点发现潜在问题,比如订阅没取消、定时器没清理,这些在生产环境可能会导致内存泄漏。 生产环境不会有这个问题,Strict Mode 的这些额外渲染只在开发模式下生效,打包上线后完全不会触发,性能零影响。 你现在的代码其实没问题,但如果你在 useEffect 里做了真实的数据请求或者订阅,记得把清理函数写好,这样即使被卸载重挂载也不会出问题: useEffect(() => { console.log('副作用执行了'); // 比如订阅事件 const subscription = someAPI.subscribe(); // 清理函数必须返回,卸载时会自动调用 return () => { subscription.unsubscribe(); }; }, []); 清理函数写好了,Strict Mode 怎么折腾都不怕。其实这个机制挺好的,相当于免费帮你做了一次压力测试,能让你在开发阶段就发现那些"只挂载不卸载"的隐患代码。 如果你实在觉得控制台日志烦人,可以加个环境变量判断,或者干脆接受这个设定,毕竟它是在帮你排查问题。不建议为了省事关掉 Strict Mode,那等于放弃了一个免费的代码质量检测工具。 回复 点赞 2 2026-03-02 18:17 加载更多 相关推荐 1 回答 39 浏览 React Strict Mode 下 useEffect 为什么会执行两次? 我最近在开发一个 React 项目,启用了 Strict Mode 后发现 useEffect 里的逻辑执行了两次,比如发请求、打日志都重复了。明明只渲染了一次组件,为啥会这样?是不是我写法有问题? ... Air-晨晰 框架 2026-03-12 19:21:21 1 回答 77 浏览 React Strict Mode为什么导致useEffect两次执行?代码没问题却报错 我在React组件里用Strict Mode包裹App时,发现useEffect里的API请求执行了两次,控制台还报错说useState未定义。但移除Strict Mode后就正常了,这是为什么? 比... ♫慧慧 框架 2026-02-19 10:09:50 2 回答 50 浏览 React 开启 Strict Mode 后 useEffect 被执行了两次,正常吗? 我在开发 React 应用时开启了 Strict Mode,结果发现组件里的 useEffect 在开发环境下执行了两次,导致接口被请求了两遍,这正常吗?我是不是哪里写错了? 这是我的代码: useE... 极客钰曦 框架 2026-02-24 22:45:17 2 回答 42 浏览 React 开启 Strict Mode 后 useEffect 为啥执行了两次? 我在开发 React 应用时,发现只要在根组件包了 StrictMode,里面的 useEffect 就会执行两次,明明只写了一次逻辑。这是 bug 吗?还是我哪里理解错了? 比如下面这段代码,在控制... 司卿 框架 2026-02-26 16:40:21 2 回答 55 浏览 React中setTimeout和useEffect的执行顺序为什么不符合预期? 我在用React写一个计数器组件,点击按钮后先调用setTimeout再更新状态,但发现useEffect里的console.log总是先于setTimeout里的输出。明明setTimeout在代码... 技术巧梅 前端 2026-02-17 22:26:26 2 回答 23 浏览 useEffect 为什么在组件首次渲染时就执行了? 我刚学 React,看到 useEffect 默认会在组件挂载后执行一次,但我不太理解为什么它不等依赖变化才运行。比如我在 Vue 里用 watch 是不会一进来就触发的,但在 React 里写了个空... 码农翌耀 框架 2026-03-02 22:19:21 1 回答 42 浏览 Jest 测试中如何正确模拟 React 组件的异步 useEffect? 我在用 Jest + React Testing Library 测试一个组件,它在 useEffect 里发起了异步请求。测试总是报“无法在未挂载的组件上执行 setState”,我试过用 awai... 令狐倩利 框架 2026-03-05 14:04:22 2 回答 77 浏览 Figma Dev Mode导出的组件样式在React中不生效怎么办? 我用Figma Dev Mode导出的按钮组件CSS,在React项目里直接复制粘贴后样式完全没效果。按钮显示成默认的方形,颜色也没变化。之前按照文档配置了正确的类名,但检查元素发现CSS变量好像没被... Mr-景叶 工具 2026-02-16 04:41:37 2 回答 46 浏览 React中使用strict-dynamic后动态内联样式还是被CSP拦截怎么办? 最近给项目加CSP防护时遇到怪事,按照文档在nonce策略里加了'strict-dynamic',但React组件里的动态内联样式还是被拦截。明明设置了nonce和函数生成样式啊... 代码大概是这样... Good“秀玲 安全 2026-01-26 23:09:29 2 回答 77 浏览 React Error Boundaries为什么在函数组件中无法捕获子组件错误? 我在React项目中用类组件实现了Error Boundary,但今天改用函数组件+useEffect模拟时,子组件报错后页面还是直接崩溃了。之前按照文档写了 componentDidCatch 方法... Des.书圻 框架 2026-02-06 10:03:16
先说结论:这是 React 18 的正常行为,不是 bug。Strict Mode 在开发环境下会故意让你的组件挂载两次、卸载两次、再挂载,用来检测你的副作用代码是否正确清理。
原理很简单,React 18 引入了一个「开发者辅助」机制:它会在第一次挂载后模拟一次「意外卸载」,然后立刻重新挂载。如果你写在 useEffect 里的代码没有返回 cleanup 函数,或者 cleanup 写得有问题(比如事件监听没移除、定时器没清理、请求没取消),这时候就能暴露出来。
说人话就是:React 在帮你检查「如果用户离开页面,你的副作用会不会留下内存泄漏或者副作用残留」。很多同学写 useEffect 时忘了 return cleanup,或者 cleanup 写错了,这个双挂载机制能帮你提前发现。
至于会不会影响生产环境——不会。生产环境下组件只挂载一次,只有开发环境+Strict Mode 才会这样。
解决方案其实就一条:确保你的 useEffect 里有正确的 cleanup。比如你代码里是模拟请求,那就应该这样写:
如果你确实没有需要清理的东西,也不用硬加 return,但最好加上注释说明为什么不需要清理,方便以后维护的人(可能就是你自己)看得懂。
Strict Mode 在开发环境下会故意把组件挂载、卸载、再挂载一次,目的是帮你检测副作用是否写得干净。React 官方这么设计是为了让你早点发现潜在问题,比如订阅没取消、定时器没清理,这些在生产环境可能会导致内存泄漏。
生产环境不会有这个问题,Strict Mode 的这些额外渲染只在开发模式下生效,打包上线后完全不会触发,性能零影响。
你现在的代码其实没问题,但如果你在
useEffect里做了真实的数据请求或者订阅,记得把清理函数写好,这样即使被卸载重挂载也不会出问题:清理函数写好了,Strict Mode 怎么折腾都不怕。其实这个机制挺好的,相当于免费帮你做了一次压力测试,能让你在开发阶段就发现那些"只挂载不卸载"的隐患代码。
如果你实在觉得控制台日志烦人,可以加个环境变量判断,或者干脆接受这个设定,毕竟它是在帮你排查问题。不建议为了省事关掉 Strict Mode,那等于放弃了一个免费的代码质量检测工具。