使用this.props.history.push传递state时目标组件中state为undefined的解决方法
看起来你在使用React Router的history.push传递state时遇到了undefined的问题,我帮你分析下问题所在,然后给出具体的修复方案:
问题根源分析
setState的异步特性导致数据过时
你先把this.state.user赋值给my_user,然后调用setState更新user,紧接着用this.state.user判断角色并传递my_user。但setState是异步执行的,这时候this.state.user还是更新前的旧值,传递的my_user自然也不是最新的用户数据,甚至可能导致角色判断错误。路由路径写法错误
你用pathname: "adminPage"这种相对路径写法,可能导致路由跳转异常,间接造成state丢失。React Router跳转路径建议用绝对路径(以/开头)。直接修改history.location属性是错误操作
代码里的this.props.history.location.pathname = "/";是无效且不规范的,不能直接修改history对象的属性,路由跳转应该用history.push或history.replace。AdminPage中未做state存在性判断
如果用户直接访问/adminPage而不是从SignInForm跳转过来,this.props.history.location.state会是undefined,直接取state.user会抛出错误。
具体修复方案
1. 修复SignInForm中的数据传递逻辑
用接口返回的response.data直接处理(这是最新的用户数据),避免依赖异步更新的this.state,同时修正路由路径:
.then(response => { if(response.status === 200){ const newUser = response.data; // 先更新state,回调里可以做后续需要依赖更新后state的操作 this.setState({ user: newUser }); // 直接用newUser判断角色,避免异步state的坑 if(newUser.roles[0].roleCode === 'ADMIN'){ this.props.history.push({ pathname: "/adminPage", // 改为绝对路径 state: { user: newUser } // 传递最新的用户数据 }); } else if(newUser.roles[0].roleCode === 'USER'){ this.props.history.push({ pathname: "/customerPage", state: { user: newUser } }); } } }) .catch(error => this.setState({error : true, message : "cannot decrypt user info"}))
2. 修复AdminPage中的state获取逻辑
添加存在性判断,避免直接访问undefined的属性,同时可以在componentDidMount里做更安全的处理:
constructor(props){ super(props); // 用可选链操作符(?.)防止state不存在时报错 this.state = { user: props.history.location.state?.user || null }; console.log(this.state.user); } componentDidMount() { // 如果没有传递state,说明用户不是通过登录跳转过来的,直接跳回登录页 if(!this.state.user){ this.props.history.push('/signin'); } }
3. 针对React Router v6的额外注意事项
如果你使用的是React Router v6,类组件不会默认接收history、location等props,需要用withRouter高阶组件包裹组件:
import { withRouter } from 'react-router-dom'; // 包裹SignInForm class SignInForm extends Component { // ...你的组件代码 } export default withRouter(SignInForm); // 包裹AdminPage class AdminPage extends Component { // ...你的组件代码 } export default withRouter(AdminPage);
关键要点总结
- 永远不要直接修改
history.location的属性,路由跳转用history.push/replace - 利用
setState的异步特性,更新后如果需要依赖新state,用setState的回调函数,或者直接使用更新前的数据源(比如接口返回的response.data) - 路由跳转路径使用绝对路径,避免相对路径导致的异常
- 获取传递的state时一定要做存在性判断,防止用户直接访问页面导致的报错
内容的提问来源于stack exchange,提问作者Tudi72

