Webpack Module Federation结合React Router:微前端模块获取查询参数
问题
主应用中配置了如下路由:
<Route path="/case/role/:caseNumber/:department" element={<RolePage />} />
RolePage组件会导入同名的微前端模块,代码如下:
import React from "react"; import { useParams, useSearchParams } from "react-router-dom"; import PageTemplate from "./PageTemplate"; const moduleName = "rolePage"; const Role = React.lazy(() => import("role_case_ui/RolePage")); export default function RolePage() { const { caseNumber, department } = useParams<{ caseNumber?: string; department?: string }>(); const [searchParams] = useSearchParams(); const sessionState = searchParams.get("sessionState"); return ( <PageTemplate appName="role_case_ui" moduleName={moduleName} displayName={caseNumber ? "Edit roles" : "New case"} > <RolePage caseNumber={caseNumber} department={department} sessionState={sessionState} /> </PageTemplate> ); }
被导入的微前端模块代码:
export default function RolePage({ ...props }: IRolePageProps) { return ( <RolePageProvider> <PageWrapper name="max-w-[1092px] mx-auto px-6 py-18 leading-xlarge tracking-wide"> <RolebPageContainer {...props} /> </PageWrapper> </RolePageProvider> ); }
访问类似/case/role/2300086/4807/?sessionState=23232的URL时,想直接在微前端模块用useSearchParams拿查询参数,但报错:
useLocation() may be used only in the context of a <Router> component.
主应用能正常用路由钩子,微前端不行,有没有办法让微前端直接获取这些参数?
解决方案
1. 继续通过props传递(最稳妥)
这是你当前在用的方式,主应用把拿到的路由参数、查询参数都通过props传给微前端组件就行。如果要加新参数,主应用扩展获取逻辑再传递即可。
比如主应用可以一次性把所有查询参数转成对象传递:
const [searchParams] = useSearchParams(); const queryParams = Object.fromEntries(searchParams.entries()); // 传递给微前端 <RolePage caseNumber={caseNumber} department={department} {...queryParams} />
微前端直接通过props接收,完全不需要依赖主应用的Router上下文,不会有冲突问题。
2. 给微前端注入Router上下文(谨慎使用)
如果微前端非要用react-router的钩子,可以在主应用里把微前端组件包裹在主应用的Router上下文里,但这种做法可能引发路由冲突,需要测试清楚:
// 主应用的RolePage组件里 import { Outlet } from 'react-router-dom'; // ... return ( <PageTemplate appName="role_case_ui" moduleName={moduleName} displayName={caseNumber ? "Edit roles" : "New case"} > <Outlet> <Role /> </Outlet> </PageTemplate> );
不过更建议让微前端脱离对主应用路由库的依赖,避免耦合。
3. 直接用浏览器原生API读取
微前端可以不借助任何路由库,直接通过window.location读取参数:
// 微前端模块里写个工具函数 const getQueryParam = (key) => { return new URLSearchParams(window.location.search).get(key); }; // 读取sessionState const sessionState = getQueryParam('sessionState'); // 从路径里提取caseNumber,根据你的URL结构调整索引 const caseNumber = window.location.pathname.split('/')[3];
这种方式简单直接,但缺点是硬编码了路径结构,如果主应用路由路径变了,微前端也要同步改。
4. 全局共享路由状态
可以通过自定义事件或者全局状态库,让主应用把路由参数同步给所有微前端:
- 主应用监听路由变化,每次路由更新时,把参数通过自定义事件发出去:
import { useLocation, useParams, useSearchParams } from 'react-router-dom'; import { useEffect } from 'react'; export default function RolePage() { const location = useLocation(); const params = useParams(); const [searchParams] = useSearchParams(); useEffect(() => { const routeData = { params, searchParams: Object.fromEntries(searchParams.entries()) }; window.dispatchEvent(new CustomEvent('routeUpdated', { detail: routeData })); }, [location, params, searchParams]); // ... 其他代码 }
- 微前端监听这个自定义事件,拿到参数后更新内部状态:
import { useEffect, useState } from 'react'; export default function RolePage() { const [routeParams, setRouteParams] = useState({}); const [searchParams, setSearchParams] = useState({}); useEffect(() => { const handleRouteUpdate = (e) => { const { params, searchParams } = e.detail; setRouteParams(params); setSearchParams(searchParams); }; window.addEventListener('routeUpdated', handleRouteUpdate); // 初始化时主动触发一次,避免微前端加载晚了没拿到初始参数 const initialParams = new URLSearchParams(window.location.search); handleRouteUpdate({ detail: { params: { caseNumber: window.location.pathname.split('/')[3], department: window.location.pathname.split('/')[4] }, searchParams: Object.fromEntries(initialParams.entries()) } }); return () => window.removeEventListener('routeUpdated', handleRouteUpdate); }, []); // ... 用routeParams和searchParams渲染组件 }
内容的提问来源于stack exchange,提问作者Ludwig
相关产品推荐
相关产品推荐

