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

React中使用Axios拦截器设置Loader状态时如何避免无限循环?

解决Axios拦截器设置Loader导致无限循环的问题

问题根源

你遇到的无限循环核心原因是:

  • 当isLoading设为true时,App组件会卸载BrowserRouter及其内部的所有路由组件(比如Home、About等)
  • 响应拦截器执行setLoading(false)后,App重渲染,路由组件重新挂载,触发组件内的API请求,再次触发请求拦截器的setLoading(true),形成循环

解决方案1:修改Loader渲染方式(核心修复)

不要用条件渲染替换路由组件,而是把Loader以叠加层的形式放在路由组件上方,这样路由组件不会被卸载,也就不会重复触发初始化请求:

修改App组件的return部分:

return (
  <>
    <BrowserRouter>
      <Routes>
        <Route path='/' element={<Layout />}>
          <Route index element={<Home />} />
          <Route path='about' element={<About />} />
          <Route path='gallery' element={<Gallery />} />
          <Route path='packages/:type' element={<Packages />} />
          <Route path='policy/:type' element={<Policy />} />
        </Route>
      </Routes>
    </BrowserRouter>
    {/* 用绝对定位/固定定位让Loader覆盖在页面上方,不影响路由组件渲染 */}
    {isLoading && <Loader />}
  </>
);

解决方案2:完善拦截器的清理与错误处理

为了避免内存泄漏,同时处理请求/响应出错的情况,给拦截器添加清理函数,并在错误分支关闭Loader:

修改useEffect部分:

useEffect(() => {
  // 保存拦截器实例,用于后续移除
  const requestInterceptor = axios.interceptors.request.use(
    (config) => {
      setLoading(true);
      return config;
    },
    (error) => {
      setLoading(false); // 请求失败也要关闭Loader
      return Promise.reject(error);
    }
  );

  const responseInterceptor = axios.interceptors.response.use(
    (response) => {
      setLoading(false);
      return response;
    },
    (error) => {
      setLoading(false); // 响应失败也要关闭Loader
      return Promise.reject(error);
    }
  );

  // 组件卸载时移除拦截器,防止内存泄漏
  return () => {
    axios.interceptors.request.eject(requestInterceptor);
    axios.interceptors.response.eject(responseInterceptor);
  };
}, []);

进阶优化:处理并发请求

如果你的应用存在多个并发API请求,当前逻辑会在第一个请求完成时就关闭Loader,这不符合预期。可以用请求计数器来管理Loader状态:

// 替换原来的isLoading状态
const [requestCount, setRequestCount] = useState(0);
const isLoading = requestCount > 0;

useEffect(() => {
  const requestInterceptor = axios.interceptors.request.use(
    (config) => {
      setRequestCount(prev => prev + 1);
      return config;
    },
    (error) => {
      setRequestCount(prev => prev - 1);
      return Promise.reject(error);
    }
  );

  const responseInterceptor = axios.interceptors.response.use(
    (response) => {
      setRequestCount(prev => prev - 1);
      return response;
    },
    (error) => {
      setRequestCount(prev => prev - 1);
      return Promise.reject(error);
    }
  );

  return () => {
    axios.interceptors.request.eject(requestInterceptor);
    axios.interceptors.response.eject(responseInterceptor);
  };
}, []);

内容的提问来源于stack exchange,提问作者Mohsin Hassan Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 15:23:08