React不同Lerna包内路由与Navigation导航失效如何修复
问题根因
- 独立包内自行创建的
history实例和主应用路由使用的history实例是完全隔离的两个对象:主应用默认使用的BrowserRouter内部会单独创建history实例,你调用独立包的history.push时,仅会修改浏览器地址栏,主应用路由监听不到该实例的变更事件,因此不会触发重新渲染。 - 如果两个包各自单独安装了
history/react-router-dom依赖,还可能因为依赖版本不一致、重复打包进一步加剧实例隔离问题。
适配方案(无需回调函数)
方案1:共享单例history,适配成本最低
无需修改现有导航调用逻辑,仅调整主应用路由配置和依赖规则即可:
- 所有Lerna子包的
package.json中,将history、react-router-dom配置为peerDependencies,统一使用主应用安装的依赖版本,避免重复打包出多份实例。 - 主应用入口放弃默认的
BrowserRouter组件,改用react-router-dom导出的底层Router组件,主动传入独立包内的公共history实例:
// 主应用入口App.js import { Router } from 'react-router-dom' // 导入独立包内的公共history实例 import history from '@MyComponents/utils/History' import Routes from './Routes' function App() { return ( <Router history={history}> <Routes /> </Router> ) }
调整完成后,独立包的导航操作和主应用路由监听的是同一个history实例,导航变更会被路由自动感知,触发对应页面渲染。
方案2:复用路由上下文能力,无额外实例维护成本
直接使用react-router内置的上下文能力获取导航实例,无需单独维护公共history:
- 独立包内将
react-router-dom设为peer依赖,类组件可以用withRouter高阶组件自动注入路由上下文的history实例:
// 独立包内MyComponent改造 import { withRouter } from 'react-router-dom' class MyComponent extends Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(c) { // 直接使用上下文注入的history实例,和主路由完全对齐 this.props.history.push('/main/' + c.name) } } // 用withRouter包裹组件,自动注入路由相关属性 export default withRouter(MyComponent)
如果是函数组件可以直接用useHistory hook,代码更简洁:
import { useHistory } from 'react-router-dom' function MyComponent() { const history = useHistory() const handleClick = (c) => history.push('/main/' + c.name) // 组件其余逻辑 }
如果你使用的是react-router v6版本,把
useHistory替换为useNavigate、history.push替换为navigate(路径)即可,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Edenco
相关产品推荐
相关产品推荐

