React router v6 如何在 axios 拦截器中使用“navigate”重定向

jan*_*w a 27 reactjs react-router-dom

import axios from "axios";
import { useNavigate } from "react-router-dom";

export const api = axios.create({
  baseURL: "http://127.0.0.1:8000/",
  headers: {
    "content-type": "application/json",
  },
});

api.interceptors.response.use(
  function (response) {
    return response;
  },
  function (er) {
    if (axios.isAxiosError(er)) {
      if (er.response) {
        if (er.response.status == 401) {

          // Won't work
          useNavigate()("/login");

        }
      }
    }

    return Promise.reject(er);
  }
);
Run Code Online (Sandbox Code Playgroud)

Dre*_*ese 27

在 RRDv6 之前的世界中,您将创建一个自定义history对象,将其导出和导入并传递给Router,并在外部 JavaScript 逻辑中导入和访问,例如 redux-thunk、axios 实用程序等。

要在 RRDv6 中复制此内容,您还需要创建一个自定义路由器组件,以便可以向其传递外部history对象。这是因为所有更高级别的 RRDv6 路由器都维护自己的内部历史上下文,因此我们需要复制历史实例化和状态部分,并传入 props 以适应基础组件Router的新 API。

import { Router } from "react-router-dom";

const CustomRouter = ({ history, ...props }) => {
  const [state, setState] = useState({
    action: history.action,
    location: history.location
  });

  useLayoutEffect(() => history.listen(setState), [history]);

  return (
    <Router
      {...props}
      location={state.location}
      navigationType={state.action}
      navigator={history}
    />
  );
};
Run Code Online (Sandbox Code Playgroud)

创建您需要的历史对象:

import { createBrowserHistory } from "history";

const history = createBrowserHistory();

export default history;
Run Code Online (Sandbox Code Playgroud)

导入并传递给新的CustomRouter

import customHistory from '../path/to/history';

...

<CustomRouter history={customHistory}>
  ... app code ...
</CustomRouter>
Run Code Online (Sandbox Code Playgroud)

在 axios 函数中导入和使用:

import axios from "axios";
import history from '../path/to/history';

export const api = axios.create({
  baseURL: "http://127.0.0.1:8000/",
  headers: {
    "content-type": "application/json",
  },
});

api.interceptors.response.use(
  function (response) {
    return response;
  },
  function (er) {
    if (axios.isAxiosError(er)) {
      if (er.response) {
        if (er.response.status == 401) {
          history.replace("/login"); // <-- navigate
        }
      }
    }

    return Promise.reject(er);
  }
);
Run Code Online (Sandbox Code Playgroud)

更新

react-router-dom导出历史路由器,即unstable_HistoryRouter.

例子:

import { unstable_HistoryRouter as HistoryRouter } from "react-router-dom";
import history from '../path/to/history';

...

<HistoryRouter history={customHistory}>
  ... app code ...
</HistoryRouter>
Run Code Online (Sandbox Code Playgroud)

笔记:

此 API 目前带有前缀,unstable_因为您可能会无意中向应用程序添加两个版本的history库,即添加到 package.json 中的版本和 React Router 内部使用的任何版本。如果您的工具允许,建议不要添加history为直接依赖项,而是依赖react-router包中的嵌套依赖项。一旦我们有了检测不匹配版本的机制,该 API 将删除其 unstable_前缀。


use*_*310 8

我遇到了同样的问题,这就是我所做的,它对我有用(基于 React router v4 的类似问题的答案

我在 React 路由器配置中添加了一个拦截器组件,它传递 useNavigate 钩子的 prop

从 axios 配置文件中删除拦截器并将它们放入单独的拦截器文件中

安装拦截器.js

//place all imports here

const SetupInterceptors = (navigate) => {
    axios.interceptors.response.use(
       function (response) {
           // Do something with response data
           return response;
       },
       function (error) {
           // Do something with response error
           if (error.response) {
                if (error.response.status === 401 || error.response.status === 403) {
                    navigate('/login');
    
                }
           }
           return Promise.reject(error);
      }
   );
};

export default SetupInterceptors;
Run Code Online (Sandbox Code Playgroud)

axiosconfigfile.js

import axios from "axios";


//axios configuration here

export default axios;
Run Code Online (Sandbox Code Playgroud)

将 AxiosInterceptorComponent 添加到 app.js

应用程序.js

import SetupInterceptors from "SetupInterceptor";
import { useState } from "react";

function NavigateFunctionComponent(props) {
    let navigate = useNavigate();
    const [ran,setRan] = useState(false);

    {/* only run setup once */}
    if(!ran){
       SetupInterceptors(navigate);
       setRan(true);
    }
    return <></>;
}


function App(props) {
   return (
       <BrowserRouter>
           {<NavigateFunctionComponent />}
           <Routes>
              {/* other routes here */}
              <Route path="/login" element={<Login/>}></Route>
              {/* other routes here */}
           </Routes>
       </BrowserRouter>
   );
}
Run Code Online (Sandbox Code Playgroud)


enc*_*nce 5

从v6.1.0开始,您可以轻松地在 React 组件之外重定向。

import {createBrowserHistory} from 'history';
import {unstable_HistoryRouter as HistoryRouter} from 'react-router-dom';

let history = createBrowserHistory();

function App() {
  return (
    <HistoryRouter history={history}>
      // The rest of your app
    </HistoryRouter>
  );
}

// Usage
history.replace('/foo');
Run Code Online (Sandbox Code Playgroud)

只需替换BrowserRouterHistoryRouter即可。

酱:https://github.com/remix-run/react-router/issues/8264#issuecomment-991271554