如何确保Ionic7+React18中无依赖useEffect仅执行一次?
React 18 + Ionic 7 中 useEffect 执行两次的问题解决
问题场景
我正在开发基于Ionic 7、React 18的应用,给useEffect传递了空依赖数组,本以为能确保副作用只执行一次,但实际UserService.getProfile()被调用了两次。
App.tsx 代码
setupIonicReact(); const App: React.FC = () => { useEffect(() => { console.log("Loading user profile info in app..." + new Date().getUTCMilliseconds()); UserService.getProfile() .then((user) => { console.log("User: " + JSON.stringify(user)); }) .catch((error) => { console.error("Error fetching profile:", error); }); }, []); return ( <IonApp> <IonReactRouter> <IonHeader> <IonToolbar> <IonButtons slot="start"> <IonButton> <IonIcon icon={logoReact} /> </IonButton> </IonButtons> <IonTitle>LOL Greetings</IonTitle> <IonButtons slot="end"> <IonButton> <IonIcon icon={search} /> </IonButton> <IonButton> <IonIcon icon={personCircle} /> </IonButton> </IonButtons> </IonToolbar> <IonToolbar> <CategorySelectComponent /> </IonToolbar> </IonHeader> <IonContent className="ion-padding" scroll-y> Test </IonContent> </IonReactRouter> </IonApp> ); }; export default App;
main.tsx 代码
const container = document.getElementById("root"); const root = createRoot(container!); root.render( <React.StrictMode> <App /> </React.StrictMode> );
原因与解决方法
原因
这是React 18严格模式(<React.StrictMode>)的开发环境特性:为了帮开发者提前发现重复执行副作用可能引发的bug,StrictMode会在开发环境中刻意重复执行useEffect等副作用逻辑,但生产环境不会有这个行为。你的代码正好用StrictMode包裹了App,所以出现了两次执行的情况。
解决方案
方案1:移除StrictMode(开发环境临时验证用)
直接修改main.tsx,去掉<React.StrictMode>包裹,开发环境下useEffect就只会执行一次:
const container = document.getElementById("root"); const root = createRoot(container!); root.render( <App /> );
注意:StrictMode能有效检测潜在问题,不建议在生产环境移除,仅作为开发时临时验证手段。
方案2:用Ref标记执行状态(推荐长期使用)
如果想保留StrictMode的优势,同时确保API只调用一次,可以用useRef记录副作用是否已执行:
setupIonicReact(); const App: React.FC = () => { const hasFetched = useRef(false); useEffect(() => { if (!hasFetched.current) { console.log("Loading user profile info in app..." + new Date().getUTCMilliseconds()); UserService.getProfile() .then((user) => { console.log("User: " + JSON.stringify(user)); }) .catch((error) => { console.error("Error fetching profile:", error); }); hasFetched.current = true; } }, []); // 其余返回代码不变... }; export default App;
这种方式既保留了StrictMode的检测能力,又能避免重复调用API,适合长期使用。
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

