改用createBrowserRouter后useNavigate报错,需兼容useBlocker与全局模态框
解决方法
方案一:将GlobalModalProvider移入RouterProvider内部
这是最直接的处理方式,让模态框组件完全处于Router上下文范围内:
- 修改App.tsx的结构,把GlobalModalProvider从RouterProvider外层移到内层:
// App.tsx import { RouterProvider } from 'react-router-dom'; import { router } from './router'; // 你用createBrowserRouter创建的路由实例 import GlobalModalProvider from './GlobalModalProvider'; function App() { return ( <RouterProvider router={router}> <GlobalModalProvider> {/* 你的根路由组件,比如Root */} </GlobalModalProvider> </RouterProvider> ); } export default App;
- 确保根路由组件(如Root)包含路由出口
<Outlet />,这样模态框可以在任意路由页面触发,同时useNavigate能正常获取Router上下文。 useBlocker的使用保持不变,直接在路由组件内调用即可,它本就处于Router上下文环境中。
方案二:传递navigate实例给GlobalModalProvider
如果无法移动ModalProvider的位置,可以手动传递navigate实例:
- 在Router内部的根组件中获取navigate,通过自定义Context传递给GlobalModalProvider:
// Root.tsx(根路由组件) import { useNavigate } from 'react-router-dom'; import { createContext, useContext } from 'react'; const GlobalModalContext = createContext<{ navigate?: ReturnType<typeof useNavigate> }>({}); function Root() { const navigate = useNavigate(); return ( <GlobalModalContext.Provider value={{ navigate }}> <Outlet /> </GlobalModalContext.Provider> ); }
- 修改GlobalModalProvider和模态框组件,使用传入的navigate代替
useNavigate:
// GlobalModalProvider.tsx import { GlobalModalContext } from './Root'; export function GlobalModalProvider({ children }: { children: React.ReactNode }) { return ( <> {children} <SettingLogout /> </> ); } // SettingLogout组件 export function SettingLogout() { const { navigate } = useContext(GlobalModalContext); const handleLogout = () => { navigate?.('/login'); }; return <button onClick={handleLogout}>退出登录</button>; }
方案三:使用unstable_HistoryRouter共享history对象
若需要ModalProvider保持在最外层,同时让useBlocker和useNavigate正常工作,可使用实验性的unstable_HistoryRouter(注意该API不稳定,生产环境需谨慎):
- 安装history包:
npm install history
- 创建history实例,用HistoryRouter包裹GlobalModalProvider和RouterProvider:
// App.tsx import { unstable_HistoryRouter as HistoryRouter } from 'react-router-dom'; import { createBrowserHistory } from 'history'; import GlobalModalProvider from './GlobalModalProvider'; import { router } from './router'; const history = createBrowserHistory(); function App() { return ( <HistoryRouter history={history}> <GlobalModalProvider> <RouterProvider router={router} /> </GlobalModalProvider> </HistoryRouter> ); } export default App;
- 此时模态框处于HistoryRouter上下文内,
useNavigate和useBlocker都能基于共享的history实例正常工作。
内容的提问来源于stack exchange,提问作者jungmin
相关产品推荐
相关产品推荐

