As mentioned in the error, hooks can only be used inside a function component. By using useNavigate
inside a function that isn't a function component would simply yield an erroneous result.
You can create a hook that intercepts requests and use useNavigate
within the resulting interception.
The code below demonstrates how to consume an axios interceptor in a react component.
Working codesandbox example: Please note that you need to open the web app in a new window instead of the codesandox iframe, since I'm using msw to simulate a 500
status code request. You can visit the non-iframe version in this link.
Navigate to the "Page with Error" link, it should send a request to a URL that responds a 500
status code. The axios interceptor should direct the page back to the /
route.
// 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 <></>;
}
To use the component above, we need to add it inside a router, the case below uses MemoryRouter
but you can freely change it to BrowserRouter
if you want to.
// 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>
);
}
The PageWithError
component also has to be defined, it simply sends a request to an API that returns 500
status code. As described in the axios interceptor hook we implemented above, it simply goes to the root page, /
.
// 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...'}</>;
}