我已经为我的服务创建了一个axios拦截器,场景是如果特定的api调用失败。它将重定向到错误组件。但是它给了我错误的Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
下面是我的agent.ts代码:
axios.defaults.baseURL = "https://localhost:5001/api/";
const responseBody = (response: AxiosResponse) => response.data;
axios.interceptors.response.use(
(response) => {
return response;
},
(error: AxiosError) => {
const { data, status }: { data: any; status: any } = error.response!;
const navigate = useNavigate();
switch (status) {
case 500:
//toast.error(data.title);
navigate("server-error");
break;
default:
break;
}
return Promise.reject(error.response);
}
);
const request = {
get: (url: string) => axios.get(url).then(responseBody),
};
const Catalog = {
list: () => request.get("products"),
};
const agent = {
Catalog,
};在我的组件中,下面是调用请求的代码:
useEffect(() => {
agent.Catalog.list().then((products) => setProducts(products));
}, []);发布于 2022-10-16 11:59:04
正如错误中提到的,钩子只能在函数组件中使用。通过在非函数组件的函数中使用useNavigate,只会产生错误的结果。
您可以创建一个钩子来拦截请求,并在结果的拦截中使用useNavigate。
下面的代码演示了如何在react组件中使用axios拦截器。
工作代码框示例:请注意,您需要在一个新窗口中打开web应用程序,而不是codesandox,因为我使用生活垃圾来模拟500状态代码请求。您可以访问非iframe版本的在这个链接中。
导航到"Page“链接,它应该向响应
500状态代码的URL发送请求。axios拦截器应该将页面引导回/路由。
// AxiosNavigation.js
import { useRef, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import axios from 'axios';
export function useAxiosNavigation() {
// Use useRef to prevent a re-render in the useEffect.
// A ref, cannot be used as a useEffect dependency, hence,
// your linters shouldn't complain about missing dependencies.
const navRef = useRef(useNavigate());
useEffect(() => {
const intercetpor = axios.interceptors.response.use(
(response) => response,
(error) => {
switch (error?.response?.status) {
case 500:
navRef.current('/');
break;
default:
}
return Promise.reject(error);
}
);
return () => {
axios.interceptors.response.eject(intercetpor);
};
}, []);
}
export default function AxiosNavigation() {
useAxiosNavigation();
return <></>;
}要使用上面的组件,我们需要在路由器中添加它,下面的例子使用MemoryRouter,但是如果您愿意,可以自由地将它更改为BrowserRouter。
// App.js
import { MemoryRouter, Routes, Route, Link } from 'react-router-dom';
import AxiosNavigation from './AxiosNavigation';
import PageWithError from './Page-With-Error';
export default function App() {
return (
<main>
<MemoryRouter>
<AxiosNavigation />
<header>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/page-with-error">Page with error</Link>
</nav>
</header>
<article>
<Routes>
<Route path="/" element={<>Home Page</>} />
<Route path="/about" element={<>About Page</>} />
<Route path="/page-with-error" element={<PageWithError />} />
</Routes>
</article>
</MemoryRouter>
</main>
);
}还必须定义PageWithError组件,它只需向返回500状态代码的API发送一个请求。正如我们在上面实现的axios拦截器钩子中所描述的那样,它只是转到根页面/。
// PageWithError.js
import axios from 'axios';
import { useState, useEffect } from 'react';
export default function PageWithError() {
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
axios
.get('/api-500-error')
.catch((error) => {
console.log('caught', error.response);
})
.finally(() => {
setLoading(false);
});
}, []);
return <>Page With Error: {loading && 'going to home page...'}</>;
}https://stackoverflow.com/questions/74085802
复制相似问题