ReactJS:componentDidMount中API调用6次的原因及解决办法
嘿,我来帮你捋捋这个问题——你的componentDidMount里的axios请求被调用了6次,这确实挺闹心的,咱们一步步拆解可能的原因,再说说解决办法和替代方案:
为啥会触发这么多次请求?
这些是最常见的几个原因,你可以对照排查:
- 组件反复挂载/卸载:如果你的组件在页面里被多次渲染、卸载再挂载(比如路由频繁切换、父组件state变化导致子组件反复重建),
componentDidMount就会跟着每次挂载执行一次请求。比如父组件的某个状态频繁更新,子组件没做优化,每次都重新挂载,次数就会叠加。 - React严格模式(Strict Mode)的锅:开发环境下,React的Strict Mode会刻意重复调用一些生命周期方法(包括
componentDidMount),用来帮你检测潜在的bug。虽然一般是两次,但如果结合了其他因素(比如组件本身被多次实例化),次数就会变多。 - 组件被多次实例化:要是你的组件在页面多个地方被使用,或者在列表循环里渲染了6次,每个实例都会执行自己的
componentDidMount,请求次数自然就和实例数一致了。 - 状态更新引发的连锁重渲染:如果请求的
then回调里调用了setState,而这个状态更新又触发了组件或父组件的重渲染,要是没做渲染优化,可能会陷入“请求→更新状态→重渲染→再请求”的循环?不过一般不会直接到6次,但叠加其他因素也有可能。
解决办法&替代方案
先搞定重复调用的根本问题
- 先确认组件挂载次数:在
componentDidMount里加一行console.log('组件挂载啦'),看看输出次数是不是6次。如果是,就去排查组件被重复实例化或者反复挂载的原因——比如是不是路由配置重复了,或者父组件的条件渲染导致它反复出现消失。 - 临时关闭Strict Mode排查:如果是开发环境,你可以把
index.js里的<React.StrictMode>标签去掉试试,看看请求次数会不会减少。不过这只是排查手段,生产环境Strict Mode不会生效,别永久去掉哦。 - 优化组件渲染:
- 类组件可以改成
PureComponent,或者自己实现shouldComponentUpdate方法,只有当props/state真的变化时才允许重渲染。 - 要是后续转成函数组件,用
React.memo包裹组件,防止不必要的重渲染。
- 类组件可以改成
- 临时用防抖/节流限制请求:虽然不是根本解决办法,但可以应急。比如用lodash的
_.debounce包裹请求,避免短时间内多次发送:
import _ from 'lodash'; componentDidMount(){ const fetchData = _.debounce(() => { axios.get(`${this.state.url}tables`, { headers: { 'authorization': token } }) .then(response => { // 处理state更新逻辑 }) }, 1000); // 1秒内只执行一次 fetchData(); }
更靠谱的生命周期/函数替代
- 类组件用
componentDidUpdate配合条件判断:如果是因为状态变化需要重新请求,别只在componentDidMount里执行,把请求抽成单独方法,然后在componentDidUpdate里判断条件再调用:
componentDidMount() { this.fetchData(); } componentDidUpdate(prevProps, prevState) { // 只有当url变化时才重新请求,避免重复调用 if (prevState.url !== this.state.url) { this.fetchData(); } } fetchData() { axios.get(`${this.state.url}tables`, { headers: { 'authorization': token } }) .then(response => { const { regions, state, directory } = response.data.data; this.setState({ regions, state, directory }); }) }
- 转用函数组件的
useEffect:如果可以重构组件,函数组件的useEffect会更灵活,通过依赖数组能精准控制请求时机。空依赖数组的话,请求只会在组件挂载时执行一次:
import { useEffect, useState } from 'react'; function YourComponent() { const [url, setUrl] = useState('你的初始url'); const [regions, setRegions] = useState([]); const [state, setState] = useState({}); const [directory, setDirectory] = useState({}); useEffect(() => { const fetchData = async () => { try { const response = await axios.get(`${url}tables`, { headers: { 'authorization': token } }); const { regions, state, directory } = response.data.data; setRegions(regions); setState(state); setDirectory(directory); } catch (err) { console.error('请求失败:', err); } }; fetchData(); }, []); // 空依赖数组,仅挂载时执行一次 // 组件渲染逻辑 return ( // ...你的JSX ); }
内容的提问来源于stack exchange,提问作者Hareesh
相关产品推荐
相关产品推荐

