React中fetch仅调用一次却发起多次网络请求问题求解
问题原因
你遇到的是React 18+版本默认开启的严格模式(Strict Mode)带来的开发环境特性,和业务逻辑本身无关。
通过create-react-app创建的新项目,默认会在入口文件index.js中把根组件包裹在<React.StrictMode>标签内,这个配置在开发环境下会故意执行两次组件渲染逻辑,用来提前暴露代码中隐藏的副作用问题。
React 18同时新增了控制台日志消噪功能,第二次渲染产生的console.log会被默认置灰隐藏,你观察到的「App()函数和logStuff()仅调用一次」是日志被过滤后的错觉,实际上两个函数都执行了两次,所以才会触发两次fetch请求和两次成功回调日志。
验证方式
打开项目的src/index.js文件,删除外层的<React.StrictMode>标签,重启服务后即可看到请求变为1次,符合预期。需要注意的是严格模式仅在开发环境生效,生产环境打包后不会出现重复执行的问题,不会影响线上使用。
最佳实践优化
你现在直接在组件return语句中执行包含fetch的副作用函数,不符合React的设计规范。所有副作用操作都应该放到useEffect钩子中执行,参考写法如下:
import { useEffect } from 'react'; import logo from './logo.svg'; import './App.css'; function App() { console.log("###? App()"); const logStuff = () => { console.log("###? Logging stuff") fetch("https://httpbin.org/post", { method: 'POST', body: JSON.stringify({error: "hello", message: "there"}), }) .then(() => console.log('###? useLog() response')) .catch((error) => { console.error('###? Failed to send log with error: ' + error); }); } // 空依赖数组代表仅在组件挂载时执行一次 useEffect(() => { logStuff(); }, []); return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo"/> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } export default App;
如果需要在严格模式开发环境下也完全避免重复执行,可以加ref标记做判断:
import { useEffect, useRef } from 'react'; // 组件内逻辑 const isExecuted = useRef(false); useEffect(() => { if (!isExecuted.current) { logStuff(); isExecuted.current = true; } }, []);
内容的提问来源于stack exchange,提问作者Przemek Lach
相关产品推荐
相关产品推荐

