React 开启 Strict Mode 后 useEffect 为啥执行了两次?

司卿 阅读 43

我在开发 React 应用时,发现只要在根组件包了 StrictMode,里面的 useEffect 就会执行两次,明明只写了一次逻辑。这是 bug 吗?还是我哪里理解错了?

比如下面这段代码,在控制台会打印两次 “mounted”:

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    console.log('mounted');
  }, []);

  return <div>Hello</div>;
}

我试过移除 StrictMode 包裹,就只打印一次了。但官方文档说 Strict Mode 不会影响生产环境,那开发时这样会不会影响调试逻辑?比如初始化请求发了两次?

我来解答 赞 12 收藏
二维码
手机扫码查看
2 条解答
萌新.宝娥
这是StrictMode故意设计的,帮你提前发现副作用问题。开发环境下它会故意mount两次组件,模拟快速mount/unmount的场景。

解决方法:
1. 如果你用useEffect做数据请求,加个取消逻辑:
useEffect(() => {
let ignore = false;
fetchData().then(data => {
if (!ignore) setData(data);
});
return () => { ignore = true; };
}, []);


2. 或者干脆别管它,生产环境会恢复正常,开发时多发一次请求就当测试了。

别慌,不是你的问题,React团队就这么设计的,习惯就好。
点赞 1
2026-03-07 02:00
司徒依甜
这不是 bug,是 StrictMode 的故意行为,专门用来帮你发现潜在问题的。

React 在开发环境下,会故意把 useEffect 的副作用函数执行两次(仅限于开发模式,生产环境完全正常),前提是组件挂载时触发的 effect。这样设计是因为很多开发者会把副作用写成“只执行一次”,但实际逻辑里可能没处理好清理逻辑,比如订阅、定时器、网络请求这些,如果组件挂载又卸载再挂载,可能就会重复触发副作用。

StrictMode 假装组件被挂载→卸载→再挂载一遍,帮你提前暴露这类问题。比如你发了两次请求,其实就说明你没在 cleanup 里取消请求,或者没做幂等处理——这在真实场景下(比如网络抖动、用户快速切换 tab)是可能发生的。

建议改成这样来避免开发时的副作用重复执行(尤其是副作用有明显外部影响时):

useEffect(() => {
const id = setTimeout(() => {
console.log('mounted');
}, 1000);

return () => {
clearTimeout(id);
};
}, []);


关键是 cleanup 里要清理掉所有可能残留的副作用。如果你只是打印日志看执行次数,完全不用管;但要是发请求、写本地存储、注册事件监听这些,就一定要在 cleanup 里处理干净。

最后提醒一句:StrictMode 的双执行只发生在开发环境,生产环境打包后(npm run buildyarn build)就完全正常了,不会多执行一次。所以别怕,大胆用 StrictMode,它是在帮你抓隐藏 bug,不是添乱。
点赞 3
2026-02-26 17:00