If you encounter the issue of needing React hooks e.g. usePathname()
in Axios interceptors but run into React’s rules of hooks error, you can resolve it by creating a React component. This approach leverages React states, effects, and hooks correctly while integrating them with Axios interceptors.
Below is an example of how to achieve this by wrapping your Axios interceptor in a React component:
import { PropsWithChildren, useEffect } from "react";
import { router, usePathname } from "expo-router";
import { useNotification } from "@/components/ui/notification";
import { api } from "./api";
export const AxiosInterceptor = ({ children }: PropsWithChildren) => {
const route = usePathname();
const unguardedRoutes = ["/login", "/register"];
const isGuardedRoute = !unguardedRoutes.includes(route);
useEffect(() => {
/* ======================================== SUCCESS RESPONSE INTERCEPTOR */
const responseInterceptor = (response: any) => {
return response.data;
};
/* ======================================== ERROR RESPONSE INTERCEPTOR */
const errorInterceptor = (e: any) => {
/* ======================================== REDIRECT */
const status = e.response?.status;
const unauthenticatedStatus = [401, 403, 409];
const isUnauthenticated = unauthenticatedStatus.includes(status);
if (isGuardedRoute && isUnauthenticated) {
router.replace("/login");
}
/* ======================================== RETURNS */
return Promise.reject(e);
};
const interceptor = api.interceptors.response.use(responseInterceptor, errorInterceptor);
return () => {
api.interceptors.response.eject(interceptor);
};
}, [isGuardedRoute]);
return children;
};
Wrap your root layout in the AxiosInterceptor
component:
import { AxiosInterceptor } from "./AxiosInterceptor";
const RootLayout = () => {
return (
<AxiosInterceptor>
<Stack>
<Stack.Screen name="(tabs)" />
<Stack.Screen name="(auth)" />
<Stack.Screen name="+not-found" />
</Stack>
</AxiosInterceptor>
);
}