React Router页面离开回调问题:props.router未定义解决方案求助
嘿,我来帮你搞定这个路由离开监听的问题!
首先得说清楚:你用的this.props.router.setRouteLeaveHook是react-router v3及更早版本的写法,而你现在用的是react-router-dom v4,这个版本已经完全重构了路由体系,原来的router prop和setRouteLeaveHook方法都被移除了,所以才会报this.props.router is undefined的错误。
不用慌,v4里有更简洁的方式实现页面离开监听,而且完全不需要用React.createClass,下面给你针对类组件的解决方案(符合你当前的技术栈):
解决方案:使用withRouter高阶组件 + history.block
- 首先导入
withRouter:
import { withRouter } from 'react-router-dom';
- 在你的类组件里,通过
componentDidMount注册离开钩子,同时在componentWillUnmount里清理(避免内存泄漏):
class YourComponent extends React.Component { componentDidMount() { // 注册路由离开拦截 this.unblock = this.props.history.block((location, action) => { // 这里写你的业务判断,比如检查是否有未保存的内容 if (this.state.hasUnsavedChanges) { // 返回字符串会触发浏览器的确认弹窗,用户确认后才会离开 return '你还有未保存的修改,确定要离开当前页面吗?'; } // 如果不需要拦截,返回true或者直接省略即可(允许导航) }); } componentWillUnmount() { // 组件卸载时清理钩子 if (this.unblock) { this.unblock(); } } render() { return ( // 你的组件内容 <div>...</div> ); } } // 一定要用withRouter包裹组件,这样才能拿到history prop export default withRouter(YourComponent);
关键说明:
withRouter会把路由相关的history、location、matchprops注入到你的组件中,这是v4里获取路由上下文的标准方式。history.block方法是v4里用来拦截路由导航的API,它接受一个回调函数:- 回调函数的参数
location是要跳转到的目标路由,action是导航类型(比如PUSH、POP)。 - 如果返回字符串,浏览器会弹出确认对话框,用户点击“确定”才会继续导航,点击“取消”则留在当前页。
- 如果返回
false,会直接阻止导航;返回true则允许导航。
- 回调函数的参数
- 不要在
componentWillMount里注册钩子:这个生命周期在React 16.3+已经被标记为不安全,而且在服务端渲染时可能会因为没有history对象报错,改用componentDidMount更安全。
额外:如果是函数组件的写法(供参考)
如果你以后换成函数组件,可以用useHistory钩子:
import React, { useEffect } from 'react'; import { useHistory } from 'react-router-dom'; function YourComponent() { const history = useHistory(); useEffect(() => { const unblock = history.block((location, action) => { if (/* 你的判断条件 */) { return '确定要离开吗?'; } }); // 组件卸载时清理钩子 return () => unblock(); }, []); return <div>...</div>; }
最后要确认你的整个应用已经被BrowserRouter(或HashRouter)包裹了,比如你的root.jsx里应该有类似这样的代码:
import { BrowserRouter as Router } from 'react-router-dom'; ReactDOM.render( <Router> <App /> </Router>, document.getElementById('root') );
内容的提问来源于stack exchange,提问作者Xero
相关产品推荐
相关产品推荐

