React Router Dom v4同组件内编程式导航报错求助
解决React Router v4中在Router所在组件内实现编程式导航的问题
我刚看了你的代码,问题出在你的AppRouter组件本身没有被Route组件包裹,所以它无法从props中获取history对象——这就是为什么你调用this.props.history.push()会抛出"history未定义"的错误。
下面给你两种可行的解决方案:
方案一:使用withRouter高阶组件
withRouter是react-router-dom提供的高阶组件,它可以把路由相关的history、location、match props注入到任何组件中,哪怕这个组件不是直接被Route渲染的。
修改你的代码步骤:
- 从react-router-dom导入
withRouter - 用
withRouter包裹你的AppRouter组件后导出
修改后的代码示例:
import React, { Component } from 'react'; import { BrowserRouter as Router, Route, Switch, withRouter } from 'react-router-dom'; // 导入withRouter import axios from 'axios'; import Pusher from 'pusher-js'; import Component1 from './Component1'; import Component2 from './Component2'; class AppRouter extends Component{ componentDidMount() { const pusher = new Pusher('8675309', { cluster: 'us2', encrypted: true }); const nav_channel = pusher.subscribe('nav'); nav_channel.bind('message', data => { // 现在this.props.history就能正常使用了 this.props.history.push(data.message) }); } ... render(){ return( <Router> <Switch> <Route path='/path1' render={() => <Component1 navigate={this.handleNavChange} />} /> <Route path="/path2" render={() => <Component2 navigate={this.handleNavChange} />} /> </Switch> </Router> ) } } // 用withRouter包裹组件后导出 export default withRouter(AppRouter);
方案二:手动创建并共享history实例
React Router v4+允许你自己创建history对象,然后传递给Router组件,这样你可以在组件的任何地方直接使用这个实例进行路由跳转,不需要依赖props。
修改步骤:
- 从
history包导入createBrowserHistory(需要先安装:npm install history) - 创建一个history实例
- 将这个实例传递给Router组件的
history属性 - 在Pusher的回调中直接调用该实例的
push方法
代码示例:
import React, { Component } from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import { createBrowserHistory } from 'history'; // 导入createBrowserHistory import axios from 'axios'; import Pusher from 'pusher-js'; import Component1 from './Component1'; import Component2 from './Component2'; // 创建history实例 const history = createBrowserHistory(); export default class AppRouter extends Component{ componentDidMount() { const pusher = new Pusher('8675309', { cluster: 'us2', encrypted: true }); const nav_channel = pusher.subscribe('nav'); nav_channel.bind('message', data => { // 直接使用history实例跳转 history.push(data.message) }); } ... render(){ return( // 将history实例传递给Router <Router history={history}> <Switch> <Route path='/path1' render={() => <Component1 navigate={this.handleNavChange} />} /> <Route path="/path2" render={() => <Component2 navigate={this.handleNavChange} />} /> </Switch> </Router> ) } }
补充说明
- 方案一更适合不需要在组件外部共享history的场景,而方案二更适合需要在多个组件或非组件文件(比如API请求、事件监听)中使用路由跳转的场景。
- 另外,确保你的Pusher消息能正确接收,可以在回调里加
console.log(data.message)验证一下,排除消息接收的问题。
内容的提问来源于stack exchange,提问作者Wally Kolcz
相关产品推荐
相关产品推荐

