React类组件使用history报错cannot read property push of undefined如何解决
报错原因
你遇到的can not read property push of undefined报错,本质是当前组件不是路由直接渲染的组件,props中没有被自动注入history对象。只有通过<Route component={CentralBar} />方式直接挂载的组件,才会默认拿到路由相关的props,非路由嵌套组件默认无法直接获取。
类组件路由跳转的几种可行方案
方案1:使用withRouter高阶组件(适用于react-router-dom v5及更早版本)
withRouter是官方提供的高阶组件,可以把路由相关的props注入到任意组件中,修改代码如下:
import React, { Component } from 'react'; // 引入withRouter import { withRouter } from 'react-router-dom'; class CentralBar extends Component { constructor(props){ super(props) this.state = {} this.someText = this.someText.bind(this); } someText(){ this.props.history.push(`/login/`); } render() { return ( <div className="crentralPanel"> {/* 注意React里要把class改成className */} <button type="button" className="btn btn-light" onClick={this.someText}>Click on Text</button> </div> ); } } // 导出时用withRouter包裹组件 export default withRouter(CentralBar);
方案2:自定义高阶组件适配react-router-dom v6
v6版本移除了withRouter,同时把history.push换成了navigate方法,你可以自行封装高阶组件适配类组件:
- 先封装通用的withRouter高阶组件:
// src/utils/withRouter.js import { useNavigate, useLocation, useParams } from 'react-router-dom'; export default function withRouter(Component) { function ComponentWithRouterProp(props) { const location = useLocation(); const navigate = useNavigate(); const params = useParams(); return <Component {...props} router={{ location, navigate, params }} />; } return ComponentWithRouterProp; }
- 修改你的组件代码:
import React, { Component } from 'react'; import withRouter from './utils/withRouter'; class CentralBar extends Component { constructor(props){ super(props) this.state = {} this.someText = this.someText.bind(this); } someText(){ // v6用navigate方法跳转 this.props.router.navigate(`/login/`); } render() { return ( <div className="crentralPanel"> <button type="button" className="btn btn-light" onClick={this.someText}>Click on Text</button> </div> ); } } export default withRouter(CentralBar);
方案3:声明式跳转(无额外业务逻辑时优先使用)
如果点击按钮不需要执行额外的业务逻辑,直接跳转的话,用官方提供的<Link>组件更符合React声明式写法规范:
import React, { Component } from 'react'; import { Link } from 'react-router-dom'; class CentralBar extends Component { render() { return ( <div className="crentralPanel"> <Link to="/login/"> <button type="button" className="btn btn-light">Click on Text</button> </Link> </div> ); } } export default CentralBar;
方案4:全局history对象(通用所有版本)
你也可以创建全局统一的history对象,任意组件都可以直接导入使用,不需要依赖props注入:
- 创建history实例:
// src/history.js // v5版本直接用history库的createBrowserHistory,v6可以用react-router-dom导出的createBrowserHistory import { createBrowserHistory } from 'history'; export default createBrowserHistory();
- 入口文件替换Router配置:
import { Router } from 'react-router-dom'; import history from './history'; import App from './App'; ReactDOM.render( <Router history={history}> <App /> </Router>, document.getElementById('root') );
- 组件中直接导入使用:
import React, { Component } from 'react'; import history from './history'; class CentralBar extends Component { someText(){ history.push('/login/'); } render() { return ( <div className="crentralPanel"> <button type="button" className="btn btn-light" onClick={this.someText.bind(this)}>Click on Text</button> </div> ); } } export default CentralBar;
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

