React Router 6:能否在RouterProvider内使用依赖useNavigate的组件?
React Router 6 集成 AxiosInterceptor 问题
问题说明
已成功配置React Router 6多路由且运行正常,但开发的AxiosInterceptor组件因依赖useNavigate钩子,必须放置在BrowserRouter上下文内部,当前无法正确集成。
现有代码
AuthRoute.tsx
import { Navigate, RouteObject } from 'react-router-dom'; const AuthRoutes: RouteObject[] = [ { path: '/', element: <Navigate to="/sign-in" /> }, { path: 'sign-in', async lazy() { const { SignIn } = await import('@/modules/auth'); return { Component: SignIn }; } }, { path: 'forget-password', async lazy() { const { ForgetPassword } = await import('@/modules/auth'); return { Component: ForgetPassword }; } }, { path: 'reset-password', async lazy() { const { ResetPassword } = await import('@/modules/auth'); return { Component: ResetPassword }; } } ]; export default AuthRoutes;
AppRoutes.tsx
const AppRoutes: RouteObject[] = [ { path: '', element: <AuthLayout />, children: [...AuthRoutes] }, { path: '', element: <AdminLayout />, children: [ { path: 'dashboard', children: DashboardRoutes } ] } ]; export default AppRoutes;
App.tsx
function App() { return ( <> <AuthContextProvider> {/* <AxiosInterceptor> */} <RouterProvider router={createBrowserRouter(AppRoutes)} /> {/* </AxiosInterceptor> */} </AuthContextProvider> </> ); } export default App;
解决方案
RouterProvider是路由上下文的提供者,useNavigate只能在该上下文内部调用。要让AxiosInterceptor正常工作,需将其作为路由元素的一部分嵌入,而非包裹RouterProvider。
方案1:新增根路由包裹
修改AppRoutes,创建包含AxiosInterceptor的根路由,将所有现有路由作为其子路由:
// AppRoutes.tsx import { Outlet } from 'react-router-dom'; import AxiosInterceptor from './AxiosInterceptor'; const AppRoutes: RouteObject[] = [ { element: ( <AxiosInterceptor> <Outlet /> </AxiosInterceptor> ), children: [ { path: '', element: <AuthLayout />, children: [...AuthRoutes] }, { path: '', element: <AdminLayout />, children: [ { path: 'dashboard', children: DashboardRoutes } ] } ] } ]; export default AppRoutes;
同时移除App.tsx中注释的AxiosInterceptor代码:
// App.tsx function App() { return ( <> <AuthContextProvider> <RouterProvider router={createBrowserRouter(AppRoutes)} /> </AuthContextProvider> </> ); } export default App;
方案2:全局布局组件集成
创建全局布局组件,将AxiosInterceptor嵌入其中,再让所有路由继承该布局:
// GlobalLayout.tsx import { Outlet } from 'react-router-dom'; import AxiosInterceptor from './AxiosInterceptor'; const GlobalLayout = () => { return ( <AxiosInterceptor> <Outlet /> </AxiosInterceptor> ); }; export default GlobalLayout;
修改AppRoutes使用全局布局:
// AppRoutes.tsx import GlobalLayout from './GlobalLayout'; const AppRoutes: RouteObject[] = [ { element: <GlobalLayout />, children: [ { path: '', element: <AuthLayout />, children: [...AuthRoutes] }, { path: '', element: <AdminLayout />, children: [ { path: 'dashboard', children: DashboardRoutes } ] } ] } ]; export default AppRoutes;
两种方案都能让AxiosInterceptor处于路由上下文内部,正常调用useNavigate钩子。
内容的提问来源于stack exchange,提问作者RAHUL KUNDU
相关产品推荐
相关产品推荐

