React Router v6 如何在axios拦截器中使用navigate实现页面重定向
根因分析
React Hook 存在严格的调用限制,useNavigate 仅可在React函数组件、自定义Hook的顶层作用域内调用。你当前将useNavigate写在普通JS模块的axios拦截器逻辑中,不在React组件的执行上下文内,因此Hook调用不生效,跳转无法执行。
解决方案
方案1:根组件内初始化拦截器(兼容所有React Router v6版本)
该方案通过在根组件中获取合法的navigate实例,传入拦截器中使用:
- 改造axios封装模块,暴露拦截器初始化方法:
// src/utils/api.js import axios from "axios"; export const api = axios.create({ baseURL: "http://127.0.0.1:8000/", headers: { "Content-Type": "application/json", }, }); // 接收外部传入的navigate实例注册响应拦截器 export const setupResponseInterceptors = (navigate) => { api.interceptors.response.use( (response) => response, (error) => { if (axios.isAxiosError(error) && error.response?.status === 401) { // 跳转登录页,replace配置可避免用户点后退回到未授权页 navigate("/login", { replace: true }); // 可选:清除本地存储的无效身份凭证 localStorage.removeItem("user_token"); } return Promise.reject(error); } ); };
- 在应用根组件(如App.jsx)中调用初始化方法:
// src/App.jsx import { useEffect } from "react"; import { useNavigate } from "react-router-dom"; import { setupResponseInterceptors } from "./utils/api"; import { Outlet } from "react-router-dom"; function App() { const navigate = useNavigate(); useEffect(() => { // 应用初始化时仅注册一次拦截器 setupResponseInterceptors(navigate); }, [navigate]); return <Outlet />; // 替换为你的应用实际布局/路由出口逻辑 } export default App;
方案2:直接调用Router实例跳转(适用于React Router v6.4+ 数据路由场景)
如果你使用createBrowserRouter定义路由,可直接导出Router实例,在拦截器中调用其内置的navigate方法,不需要依赖Hook:
- 导出路由实例:
// src/router/index.js import { createBrowserRouter } from "react-router-dom"; import Login from "../pages/Login"; import Home from "../pages/Home"; export const router = createBrowserRouter([ { path: "/login", element: <Login /> }, { path: "/", element: <Home /> }, // 其余路由配置 ]);
- 拦截器中直接使用Router实例跳转:
// src/utils/api.js import axios from "axios"; import { router } from "../router"; export const api = axios.create({ baseURL: "http://127.0.0.1:8000/", headers: { "Content-Type": "application/json", }, }); api.interceptors.response.use( (response) => response, (error) => { if (axios.isAxiosError(error) && error.response?.status === 401) { router.navigate("/login", { replace: true }); localStorage.removeItem("user_token"); } return Promise.reject(error); } );
内容的提问来源于stack exchange,提问作者januw a
相关产品推荐
相关产品推荐

