React 18 StrictMode:组件挂载时发起API请求的最优方案
React 18严格模式下组件挂载仅发起一次API请求的更优方案
React 18的严格模式在开发环境会触发useEffect两次执行,用来检测潜在的生命周期bug。你当前用useRef标记的方法能解决问题,但还有更贴合React设计或更简洁的方案:
方法一:用AbortController处理请求取消(推荐生产环境使用)
严格模式的两次执行是模拟组件卸载后重新挂载,用AbortController可以在第二次执行前取消第一次的请求,既符合React的生命周期设计,又能避免无效请求的副作用,生产环境只会执行一次:
import { useEffect } from "react"; const App = () => { useEffect(() => { const controller = new AbortController(); const signal = controller.signal; fetch("https://jsonplaceholder.typicode.com/todos/1", { signal }) .then((response) => response.json()) .then((json) => console.log(json)) .catch((error) => { // 忽略严格模式下的中止错误 if (error.name !== 'AbortError') { console.error('请求出错:', error); } }); // 清理函数:组件卸载或严格模式二次执行前取消请求 return () => controller.abort(); }, []); return <></>; }; export default App;
方法二:封装自定义Hook提升复用性
如果多个组件需要这个逻辑,把判断逻辑封装成自定义Hook,让组件代码更干净:
import { useEffect, useRef } from "react"; // 自定义Hook:仅在组件挂载时执行一次回调 function useMountEffect(callback) { const hasRun = useRef(false); useEffect(() => { if (!hasRun.current) { hasRun.current = true; callback(); } }, [callback]); } // 组件中使用 const App = () => { useMountEffect(() => { fetch("https://jsonplaceholder.typicode.com/todos/1") .then((response) => response.json()) .then((json) => console.log(json)); }); return <></>; }; export default App;
方法三:实验性API useEffectEvent(谨慎使用)
React 18提供了实验性的useEffectEvent,能把回调从useEffect依赖中分离,确保严格模式下仅执行一次,但该API尚未稳定,不建议生产环境使用:
import { useEffect, useEffectEvent } from "react"; const App = () => { const fetchData = useEffectEvent(() => { fetch("https://jsonplaceholder.typicode.com/todos/1") .then((response) => response.json()) .then((json) => console.log(json)); }); useEffect(() => { fetchData(); }, []); return <></>; }; export default App;
你的原有方法是有效的,但上述方案中,方法一最符合React的设计原则,还能预防内存泄漏;方法二则更适合多组件复用场景。
内容的提问来源于stack exchange,提问作者Siddhartha Gaur
相关产品推荐
相关产品推荐

