react-router-dom v6类组件如何实现登录后页面重定向
问题根因
react-router-dom v6 已移除v5版本默认给类组件注入的history prop,同时废弃history.push()跳转写法,统一用navigate方法处理路由导航,直接访问this.props.history会得到undefined,触发Cannot read properties of undefined (reading 'push')报错。
v6版本类组件实现登录后跳转的可行方案
不需要降级到v5版本,以下两种都是官方兼容的稳定写法:
方案1:自定义withRouter高阶组件注入navigate(推荐,改动最小)
v6没有内置类组件用的withRouter方法,自己封装一个高阶组件,把hooks提供的navigate注入到类组件props中即可,不需要大幅修改原有业务逻辑。
首先封装高阶组件:
import { useNavigate } from 'react-router-dom'; import React from 'react'; export const withRouter = (WrappedComponent) => { return function RouterWrapper(props) { const navigate = useNavigate(); // 可按需注入useLocation、useParams等其他路由能力 return <WrappedComponent {...props} navigate={navigate} />; }; };
修改Auth组件代码:
- 引入封装好的withRouter,导出组件时用它包裹
- 把原有报错的
this.props.history.push('/dashboard')替换为this.props.navigate('/dashboard')
核心修改片段:
// 引入withRouter,路径替换为你实际存放高阶组件的文件路径 import { withRouter } from './utils/withRouter'; class Auth extends Component { constructor(props) { super(props); this.state = { tab: 'signin' } } SignIn = (email, password) => { axios.post('/api/users/login', {email, password}).then(res => { if(res.data.success) { store.dispatch({ type: 'login', _id: res.data.user._id, user: res.data.user, token: res.data.token }); // 替换原有history.push逻辑 this.props.navigate('/dashboard'); } }).catch(er => { if (er.response) { console.log(er.response.data); console.log(er.response.status); console.log(er.response.headers); } else if (er.request) { console.log(er.request); } else { console.log('er', er.message); } console.log(er.config); }) } // 其余组件逻辑(render、其他方法)保持不变 } // 导出时用withRouter包裹 export default withRouter(Auth);
如果需要实现v5中history.replace的效果(跳转后不保留当前页在历史栈),调用this.props.navigate('/dashboard', { replace: true })即可。
方案2:通过状态控制渲染Navigate组件(无需封装额外工具函数)
利用v6内置的<Navigate>组件,通过组件状态控制跳转时机,不需要写高阶组件或者hooks封装:
- 在组件state中新增跳转标记字段
- 登录成功后更新state,设置跳转目标路径
- render方法中优先判断跳转标记,满足条件时返回Navigate组件完成跳转
核心修改片段:
// 引入Navigate组件 import { Navigate } from 'react-router-dom'; class Auth extends Component { constructor(props) { super(props); this.state = { tab: 'signin', redirectPath: '' // 新增跳转路径状态 } } SignIn = (email, password) => { axios.post('/api/users/login', {email, password}).then(res => { if(res.data.success) { store.dispatch({ type: 'login', _id: res.data.user._id, user: res.data.user, token: res.data.token }); // 更新状态触发重渲染,执行跳转 this.setState({ redirectPath: '/dashboard' }); } }).catch(er => { // 原有错误处理逻辑保持不变 if (er.response) { console.log(er.response.data); console.log(er.response.status); console.log(er.response.headers); } else if (er.request) { console.log(er.request); } else { console.log('er', er.message); } console.log(er.config); }) } render() { // 优先判断是否需要跳转 if (this.state.redirectPath) { // 需要替换历史栈就加replace属性 return <Navigate to={this.state.redirectPath} replace /> } // 原有登录页渲染逻辑保持不变 return ( <div> {/* 原有的登录/注册表单内容 */} </div> ) } }
内容的提问来源于stack exchange,提问作者adarsh augustine
相关产品推荐
相关产品推荐

