组件挂载时useEffect调用两次,已用useCallback仍未解决
解决方案:在React StrictMode下避免重复执行API调用
在React开发环境的StrictMode中,React会刻意重复调用useEffect、组件挂载逻辑等,以此帮助检测潜在bug。要在保留StrictMode的前提下让API调用只执行一次,可通过以下几种方式实现:
方法1:使用Ref标记执行状态
利用useRef存储执行状态标记,Ref的引用在组件生命周期内稳定且更新不会触发重渲染:
import { useCallback, useEffect, useRef } from 'react'; function YourComponent() { const isCalled = useRef(false); const sendCode = useCallback(() => { console.log('InsideSendCode'); // 替换为你的API调用逻辑 }, []); useEffect(() => { if (!isCalled.current) { sendCode(); isCalled.current = true; } }, [sendCode]); return <div>Your Component</div>; }
原理:第一次触发useEffect时标记为未执行,调用sendCode后更新标记;第二次StrictMode触发useEffect时,因标记已为true直接跳过执行。
方法2:简化逻辑(无需复用sendCode时)
如果sendCode仅用于本次挂载逻辑,可直接将逻辑放入useEffect并配合Ref控制:
import { useEffect, useRef } from 'react'; function YourComponent() { const isCalled = useRef(false); useEffect(() => { if (!isCalled.current) { console.log('InsideSendCode'); // 你的API调用逻辑 isCalled.current = true; } }, []); return <div>Your Component</div>; }
方法3:封装自定义Hook(多组件复用场景)
如果多个组件需要类似“仅挂载执行一次”的逻辑,可封装成自定义Hook:
import { useEffect, useRef } from 'react'; function useMountOnce(callback) { const isExecuted = useRef(false); useEffect(() => { if (!isExecuted.current) { callback(); isExecuted.current = true; } }, [callback]); } // 使用示例 function YourComponent() { const sendCode = useCallback(() => { console.log('InsideSendCode'); // API调用逻辑 }, []); useMountOnce(sendCode); return <div>Your Component</div>; }
注意事项
- 该方案仅针对开发环境StrictMode的重复执行问题,生产环境中React不会触发此类重复调用,无额外性能开销。
- 不要用
useState标记执行状态,setState会触发组件重渲染,可能导致不必要的渲染循环。
内容的提问来源于stack exchange,提问作者Daniciuc Razvan
相关产品推荐
相关产品推荐

