React Router Dom v6.4+ 如何替换history.listen等API适配新数据API?
微前端(Module Federation)下适配react-router-dom v6.4+的路由同步方案
核心问题分析
在Module Federation微前端架构中,远程应用依赖memory history管理内部路由,原本通过history.listen监听路径变化,再通知宿主容器同步更新browser history。但react-router-dom v6.4+彻底废弃了useHistory、UNSAFE_NavigationContext等临时兼容方案,且新的createMemoryRouter/createBrowserRouterAPI不再直接暴露history实例,导致原有路由同步逻辑完全失效。
适配v6.4+新API的解决方案
1. 远程应用:用useNavigationListener替代history.listen
react-router-dom v6.4+提供的useNavigationListener钩子可直接监听导航行为,完美替代原history.listen的功能:
// 远程应用路由配置文件 import { createMemoryRouter, RouterProvider, useNavigationListener } from 'react-router-dom'; // 路由同步监听组件,负责将远程路由变化通知宿主 const RouteSyncListener = ({ onNavigate }) => { useNavigationListener(({ location, action }) => { // 传递当前memory history的路径和导航动作给宿主 onNavigate({ location, action }); }); return null; }; // 定义远程应用内部路由 const routes = [ { path: '/remote-app/home', element: <RemoteHome /> }, { path: '/remote-app/profile', element: <RemoteProfile /> } ]; // 远程应用入口组件 export const RemoteApp = ({ onNavigate, initialPath }) => { // 创建memory router,初始化路径从宿主传递过来 const router = createMemoryRouter(routes, { initialEntries: [initialPath || '/remote-app/home'] }); return ( <RouterProvider router={router}> <RouteSyncListener onNavigate={onNavigate} /> {/* 远程应用页面内容 */} </RouterProvider> ); };
2. 宿主容器:通过useRouter接收同步信号并更新路由
宿主使用createBrowserRouter后,可通过useRouter获取路由实例,调用navigate方法同步远程应用的路由变化:
// 宿主容器路由配置文件 import { createBrowserRouter, RouterProvider, useRouter } from 'react-router-dom'; import { RemoteApp } from 'remote-app/RemoteApp'; // 宿主路由配置 const routes = [ { path: '/', element: <HostHome /> }, { path: '/remote-app/*', element: <RemoteAppWrapper /> } ]; const router = createBrowserRouter(routes); // 远程应用包裹组件,负责传递同步回调和初始路由 const RemoteAppWrapper = () => { const hostRouter = useRouter(); const handleRemoteNavigate = ({ location, action }) => { const targetPath = location.pathname + location.search + location.hash; // 根据远程的导航动作,对应宿主的路由更新方式 if (action === 'PUSH') { hostRouter.navigate(targetPath); } else if (action === 'REPLACE' || action === 'POP') { hostRouter.navigate(targetPath, { replace: true }); } }; // 传递宿主当前路由作为远程应用的初始路径 const initialPath = hostRouter.location.pathname + hostRouter.location.search + hostRouter.location.hash; return <RemoteApp onNavigate={handleRemoteNavigate} initialPath={initialPath} />; }; // 宿主入口组件 export const HostApp = () => { return <RouterProvider router={router} />; };
3. 边界场景处理
- 路由前缀一致性:确保远程应用的路由前缀(如
/remote-app/)与宿主配置的路由规则完全匹配,避免路由冲突 - 浏览器前进/后退:通过判断
action为POP时使用replace: true,保证宿主路由与浏览器历史栈同步 - 路由参数共享:如果需要传递路由参数,可在
onNavigate回调中一并传递,宿主和远程应用自行解析处理
内容的提问来源于stack exchange,提问作者Optionwiz
相关产品推荐
相关产品推荐

