React使用<Redirect to='/profile'/>跳转时报TypeError undefined问题
报错原因排查与解决方案
你遇到的TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))报错本质是代码中尝试对undefined执行迭代操作(比如数组解构、for-of遍历、展开运算符等),结合你的场景和代码,问题根源和对应修复方案如下:
1. 路由path数组兼容性问题
你给首页Route的path属性传了数组["/", "/home"],这个特性仅在react-router-dom v5.1.0及以上版本支持,如果你项目依赖的是更低版本的v5,甚至是v4版本,就会触发路由内部处理path时的迭代报错。
修复方案:
拆成两个独立的Route即可,无需使用数组写法:
<Route exact path="/" render={() => ( currentUser ? <Redirect to="/profile" /> : <LoginPage/> )} /> <Route exact path="/home" render={() => ( currentUser ? <Redirect to="/profile" /> : <LoginPage/> )} />
2. 组件渲染时序冲突,状态未兜底
componentDidMount生命周期在组件第一次渲染完成后才会执行,你的初始状态下showBoard = undefined、currentUser = false,如果重定向跳转时,路由在setState执行完成前就完成匹配,就会因为给Route传入undefined的component属性触发异常。
同时你写的Route同时传入了component属性和子元素,react-router v5中子元素优先级高于component属性,这个冲突写法本身就会导致不可预期的错误。
另外你存在state里的组件变量名是小写开头的showBoard,在JSX中直接使用会被React识别为原生DOM标签,无法正常渲染组件。
修复方案:
// 1. 修改初始状态,加加载态避免未初始化就渲染路由 constructor(props) { super(props); this.logOut = this.logOut.bind(this); this.state = { BoardComponent: null, // 组件变量大写开头 currentUser: null, isLoading: true }; } // 2. componentDidMount加字段兜底判断 componentDidMount() { const user = AuthService.getCurrentUser(); if (user) { // 先判断roles是否为数组,避免undefined调用方法报错 const isStudent = Array.isArray(user.roles) && user.roles.includes("ROLE_STUDENT"); this.setState({ currentUser: user, BoardComponent: isStudent ? BoardStudent : BoardTeacher, isLoading: false }); } else { this.setState({isLoading: false}) } } // 3. 调整render内的路由写法,移除冲突属性,加渲染兜底 render() { const { currentUser, BoardComponent, isLoading } = this.state; if (isLoading) return <div>加载中...</div>; return ( <div className="main-site-container"> <Settings/> <Switch> <Route exact path="/" render={() => ( currentUser ? <Redirect to="/profile" /> : <LoginPage/> )} /> <Route exact path="/home" render={() => ( currentUser ? <Redirect to="/profile" /> : <LoginPage/> )} /> <Route exact path="/login" render={() => ( currentUser ? <Redirect to="/profile" /> : <LoginPage/> )} /> <Route exact path="/register" component={RegistrationPage} /> <Route exact path="/register/form" component={FormsPage} /> <Route exact path="/profile" component={Profile} /> <Route path="/user" render={() => ( BoardComponent ? <BoardComponent /> : <Redirect to="/login" /> )} /> </Switch> </div> ); }
3. 角色字段无兜底判断
你直接调用user.roles.includes没有做类型校验,如果后端返回的用户信息中roles字段为undefined、或者是非数组类型(比如直接返回字符串"ROLE_STUDENT"而非数组包裹),尝试对其调用数组方法或迭代时就会触发报错。上面的修复代码中已经加入了Array.isArray(user.roles)的兜底判断,无需额外修改。
为什么刷新页面后报错自动消失?
刷新页面时App组件会重新挂载,componentDidMount会在路由渲染前就完成状态初始化(localStorage的用户信息是同步读取的),所以状态是完整的,不会出现undefined的情况。而重定向走的是前端路由跳转,App组件不会重新挂载,状态更新的时序差就会触发初始化undefined的问题。
内容的提问来源于stack exchange,提问作者RootAtKali
相关产品推荐
相关产品推荐

