React Strict Mode 下 useEffect 为什么会执行两次?
我最近在开发一个 React 项目,启用了 Strict Mode 后发现 useEffect 里的逻辑执行了两次,比如发请求、打日志都重复了。明明只渲染了一次组件,为啥会这样?是不是我写法有问题?
我的代码结构大概是这样的:
import { useEffect, useState } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
console.log('Fetching data...');
fetch('/api/data').then(res => res.json()).then(setData);
}, []);
return <div>{data ? data.name : 'Loading...'}</div>;
}
本地开发环境用的是 React 18,包裹了 <React.StrictMode>。去掉 Strict Mode 就正常了,但又怕以后上线出问题。这到底该怎么处理?
React 18 在开发模式的 Strict Mode 下会故意挂载组件两次、卸载一次、再挂载一次,用来检测你的副作用代码是否写得"干净"——也就是有没有做好清理工作。他们希望通过这种方式逼迫你写出能在组件卸载时正确清理的代码。
你那个 fetch 请求没有做取消处理,所以第二次挂载时前一个请求还在跑,就会出现重复请求的问题。
改一下就行,加 AbortController:
这样即使 effect 被执行多次,之前的请求也会被取消,不会出现竞态问题。返回的那个函数就是 cleanup 函数,React 会在组件卸载或者下次 effect 执行前调用它。
线上生产环境不会有这个问题,Strict Mode 只在开发环境生效。但这个设计确实挺烦人的,不过长期来看是好事,能帮你发现潜在的内存泄漏和竞态条件。