[英]React-router-dom v6 useNavigate not use the axios interceptor
[英]React router v6 how to use `navigate` redirection in axios interceptor
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);
}
);
在 RRDv6 之前的世界中,您將創建一個自定義history
對象,將其導出和導入並傳遞給Router
,並在外部 javascript 邏輯中導入和訪問,例如 redux-thunks、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}
/>
);
};
創建您需要的歷史對象:
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default history;
導入並傳遞給新的CustomRouter
:
import customHistory from '../path/to/history';
...
<CustomRouter history={customHistory}>
... app code ...
</CustomRouter>
在您的 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);
}
);
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>
筆記:
這個 API 當前的前綴是
unstable_
的,因為你可能會無意中將兩個版本的history
庫添加到你的應用程序中,一個是你添加到你的 package.json 中的,另一個是 React Router 內部使用的任何版本。 如果您的工具允許,建議不要將history
添加為直接依賴項,而是依賴react-router
包中的嵌套依賴項。 一旦我們有了檢測不匹配版本的機制,這個 API 就會刪除它的unstable_
_前綴。
我遇到了同樣的問題,這就是我所做的,它對我有用(基於對 react router v4 的類似問題的回答
我在反應路由器配置中添加了一個攔截器組件,它傳遞了 useNavigate 鈎子的道具
從 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;
axiosconfigfile.js
import axios from "axios";
//axios configuration here
export default axios;
將 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>
);
}
從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');
只需將BrowserRouter
替換為HistoryRouter
即可。
醬料: https ://github.com/remix-run/react-router/issues/8264#issuecomment-991271554
這不起作用的原因是因為您只能在React 組件或自定義鈎子中使用鈎子。
由於兩者都不是,因此useNavigate()
掛鈎失敗。
我的建議是將整個邏輯包裝在自定義掛鈎中。
偽代碼:
import { useCallback, useEffect, useState } from "react"
export default function useAsync(callback, dependencies = []) {
const [loading, setLoading] = useState(true)
const [error, setError] = useState()
const [value, setValue] = useState()
// Simply manage 3 different states and update them as per the results of a Promise's resolution
// Here, we define a callback
const callbackMemoized = useCallback(() => {
setLoading(true)
setError(undefined)
setValue(undefined)
callback()
// ON SUCCESS -> Set the data from promise as "value"
.then(setValue)
// ON FAILURE -> Set the err from promise as "error"
.catch((error)=> {
setError(error)
useNavigate()('/login')
})
// Irresp of fail or success, loading must stop after promise has ran
.finally(() => setLoading(false))
// This function runs everytime some dependency changes
}, dependencies)
// To run the callback function each time it itself changes i.e. when its dependencies change
useEffect(() => {
callbackMemoized()
}, [callbackMemoized])
return { loading, error, value }
}
在這里,只需將您的 axios 調用作為回調傳遞給鈎子。
對於從 v5 遷移到 v6 的 react 路由器的參考,此視頻很有幫助
從 6.1.0 版本開始,React Router 有一個unstable_HistoryRouter
的HistoryRouter。 有了它, history
現在可以再次在 React 上下文之外使用。 它是這樣使用的:
// lib/history.js
import { createBrowserHistory } from "history";
export default createBrowserHistory();
// App.jsx
import { unstable_HistoryRouter as HistoryRouter } from 'react-router-dom';
import history from "lib/history";
function App() {
return (
<HistoryRouter history={history}>
// The rest of your app
</HistoryRouter>
);
}
// lib/axios.js
import history from "lib/history";
import storage from "utils/storage";
export const axios = Axios.create({})
axios.interceptors.response.use(
(response) => {
return response.data;
},
(error) => {
if (error.response?.status === 401) {
storage.clearToken();
history.push("/auth/login");
return Promise.resolve();
}
return Promise.reject(error);
}
);
當被問及unstable_
-prefix 是什么意思時,其中一位維護者回答:
不穩定的前綴只是表示您可能會遇到由於 react-router 請求本身的歷史版本不匹配而導致的錯誤。 雖然實際影響可能只是產生類型問題(歷史版本之間的不同類型),但也可能存在導致更細微錯誤的 API 或行為更改(例如如何解析 URL,或如何生成路徑)。
只要您密切關注 react-router 請求的歷史版本並確保它與您的應用程序使用的版本同步,您就應該沒有問題。 我們還沒有針對不匹配的保護或警告,因此我們現在稱之為不穩定。
有一些關於 react-router-v4 的很好的答案,我認為這對一些修改最少的人非常有用。
我通過為攔截器創建一個組件解決了這個問題:
import { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { axiosInstance } from '../custom-axios';
export const ResponseInterceptor = () => {
const { onLogout } = useAuth();
const { addError } = useAPIError();
const navigate = useNavigate()
const interceptorId = useRef<number | null>(null);
useEffect(() => {
interceptorId.current = axiosInstance.interceptors.response.use(undefined, (error) => {
switch (error.response.status) {
case 401:
navigate('/login');
break;
}
});
return () => {
axiosInstance.interceptors.response.eject(interceptorId.current as number);
};
}, []);
return null;
};
並將其連接到 App 組件:
const App = () => {
return (
<AuthProvider>
<APIErrorProvider>
<AppRoutes />
<ResponseInterceptor />
<APIErrorNotification />
</APIErrorProvider>
</AuthProvider>
);
};
export default App;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.