You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useEffect挂载时重复发起API请求问题求助

页面加载时API请求两次的原因及解决办法

1. 最常见的原因:React Strict Mode

React 18的Strict Mode在开发环境下会强制组件双重渲染(包括useEffect的执行),目的是帮你提前发现未清理的副作用、重复创建的资源等潜在问题。这种双重渲染仅存在于开发阶段,生产环境不会出现。

你可以检查项目入口文件(比如index.js),看是否用StrictMode包裹了根组件:

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

如果是这个原因,要么接受开发环境的两次请求(生产环境正常),要么暂时移除StrictMode验证(不推荐长期这么做,因为它能帮你规避很多bug)。

2. 函数依赖导致的意外触发

你当前的useEffect依赖是空数组,但fetchData是在组件内部定义的函数——组件每次渲染都会重新创建这个函数。虽然你没把它放进依赖数组,但React的hooks lint规则会警告你遗漏了依赖,这种未声明的依赖可能导致useEffect在某些场景下重复执行。

解决办法是用useCallback包裹fetchData,并将其加入useEffect的依赖数组:

const fetchData = useCallback(async () => {
  // 你的API请求逻辑
  const response = await yourApiRequest();
  setData(response.data);
}, []); // 根据实际需求添加依赖,比如API请求所需的参数、token等

useEffect(() => {
  fetchData();
}, [fetchData]);

这样能保证fetchData仅在依赖变化时重新创建,避免不必要的useEffect触发。

3. 子组件意外调用了fetchData

你把fetchData传递给了子组件,要检查子组件是否在挂载过程中(比如自身的useEffect)或者渲染流程里不小心执行了fetchData(),导致父组件的useEffect触发一次,子组件又触发一次,最终出现两次请求。

可以在fetchData里添加调用栈打印,定位触发源:

const fetchData = async () => {
  console.log('fetchData调用来源:', new Error().stack);
  // 你的API请求逻辑
  const response = await yourApiRequest();
  setData(response.data);
};

通过打印的调用栈,就能清楚看到请求是父组件触发的,还是子组件触发的。

额外优化:避免请求竞态

无论哪种情况,都建议给useEffect添加清理逻辑,防止组件卸载或重复渲染时的请求竞态问题:

useEffect(() => {
  let isComponentMounted = true;

  const fetch = async () => {
    const response = await yourApiRequest();
    // 仅在组件挂载状态下更新数据
    if (isComponentMounted) {
      setData(response.data);
    }
  };

  fetch();

  // 组件卸载时标记状态
  return () => {
    isComponentMounted = false;
  };
}, []);

这样能避免已卸载的组件更新状态,也能在重复请求时忽略旧的响应。


内容的提问来源于stack exchange,提问作者Grayson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 11:32:34