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

问题描述 投票:0回答:1

我正在开发一个 React 应用程序,我需要在使用 Axios 拦截器的 API 调用期间显示加载程序。但是,我遇到了一个问题,即在收到响应后将加载器状态设置为 false 会导致无限循环。

这是我的代码:

import React, { useEffect, useState } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import axios from 'axios';
import { Home, About, Gallery, Packages, Policy } from './pages';
import './App.css';
import Layout from '../Layout.jsx';
import Loader from './components/Loader';


function App() {
  const [isLoading, setLoading] = useState(false)

  useEffect(() => {
    axios.interceptors.request.use(function (config) {
      console.log(config)
      setLoading(true)
      return config;
    }, function (error) {
      return Promise.reject(error);
    });


    axios.interceptors.response.use(function (response) {
       // setLoading(false)
       console.log(response)
       return response;

    }, function (error) {

     return Promise.reject(error);
    })


  },[])

  return (
    <>
      {isLoading ? (
        <Loader />
      ) : (
        <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>
      )}
    </>
  );
}

export default App;

仅当 setLoading(false) 取消注释时才会出现无限循环。

我实现了 Axios 拦截器,在请求开始时将 isLoading 状态设置为 true,在收到响应时将 isLoading 状态设置为 false。

在响应拦截器中设置setLoading(false)时,加载器会进入显示和隐藏的无限循环。这个问题似乎是由拦截器中的状态更新触发的连续重新渲染引起的。

reactjs react-hooks axios
1个回答
0
投票

发生无限循环是因为在 axios 拦截器内设置状态(如 setLoading(false))会导致组件重新渲染。重新渲染时,useEffect 钩子会重新执行,重新注册拦截器,这会再次导致状态更改,从而创建无限循环。为了避免这种情况,您应该添加仅注册一次的拦截器。以下是您可以做到这一点的方法,

添加use ref来存储拦截器注册状态

  const isInterceptorRegistered = useRef(false);

在你的 useEffect 挂钩中执行此更改,

 useEffect(() => {
if (!isInterceptorRegistered.current) {
  isInterceptorRegistered.current = true;

  // Request interceptor
  const requestInterceptor = axios.interceptors.request.use(
  //
  );

  // Response interceptor
  const responseInterceptor = axios.interceptors.response.use(
  //
  );

  // Cleanup interceptors on unmount
  return () => {
    axios.interceptors.request.eject(requestInterceptor);
    axios.interceptors.response.eject(responseInterceptor);
  };
}


 }, []); 
© www.soinside.com 2019 - 2024. All rights reserved.