React登录表单遇Maximum update depth exceeded错误求非Redux解决方案
解决React中重定向导致的无限循环问题
我来帮你分析一下问题所在,然后给出具体的解决办法。
问题根源
你现在在render方法里直接返回<Redirect />,当userId存在时,每次组件渲染都会触发路由跳转。而跳转之后,这个组件又会重新进入渲染流程(要么是路由跳转导致组件重新挂载,要么是状态更新触发重渲染),然后再次触发userId判断和重定向,形成了无限循环,这就是为什么会出现Maximum update depth exceeded错误。
解决方案:把重定向逻辑移到生命周期方法中
路由跳转属于「副作用操作」,不应该放在render里(render应该是纯函数,只负责根据状态返回UI)。我们可以把重定向的判断放到类组件的生命周期方法里,比如componentDidMount(组件挂载时)和componentDidUpdate(状态更新时),这样只会在特定时机执行一次跳转,避免循环。
修改步骤:
- 确保你的组件能获取到
history对象(需要用react-router-dom的withRouter高阶组件包裹) - 新增生命周期方法,在合适的时机检查
userId并执行跳转 - 把
render里的重定向逻辑移除,只保留正常的UI渲染
修改后的代码示例:
import React, { Component } from 'react'; import { withRouter } from 'react-router-dom'; // 引入withRouter class YourComponent extends Component { state = { name: "", email: "", password: "", password2: "", errors: null, image: null, imageName: null, token: localStorage.getItem('token'), userId: localStorage.getItem('userId') }; // 组件挂载时检查是否需要重定向 componentDidMount() { this.handleRedirect(); } // 状态更新时,只有userId变化才检查重定向 componentDidUpdate(prevProps, prevState) { if (prevState.userId !== this.state.userId) { this.handleRedirect(); } } // 封装重定向逻辑 handleRedirect = () => { if (this.state.userId !== null) { this.props.history.push('/login'); // 使用history.push跳转,不会触发无限循环 } } onSubmit = async e => { e.preventDefault(); this.setState({ errors: null }); if (this.state.password !== this.state.password2) { this.setState({ errors: "Password and Confirm Password Are Invalid" }); } else { const newUser = { email: this.state.email, password: this.state.password, name: this.state.name, image: this.state.imageName, }; try { const config = { headers: { "Content-Type": "application/json" } }; const body = newUser; const res = await axios.post('api/addUser', body, config); const token = res.data.token; const decoded = jwt_decode(token); const userId = decoded.user.id; // 先存localStorage,再更新state localStorage.setItem('userId', userId); localStorage.setItem('token', token); // 合并两次setState,避免不必要的重渲染 this.setState({ token: token, userId: userId }); } catch (error) { console.log(error.message); } } }; render() { // 这里只渲染正常的UI,不再处理重定向 return ( <div>Welcome</div> ) } } // 用withRouter包裹组件,让它能获取到history props export default withRouter(YourComponent);
额外优化点
我注意到你在onSubmit里有两次setState,可以合并成一次,减少不必要的组件重渲染。另外,await不需要加在localStorage.setItem前面,因为它是同步方法。
为什么这样能解决问题?
componentDidMount只会在组件第一次挂载时执行一次,检查初始的userId状态componentDidUpdate只会在userId发生变化时才执行跳转逻辑,不会每次渲染都触发- 使用
history.push跳转,不会像Redirect组件那样在render里触发重复渲染,从根源上避免了无限循环
内容的提问来源于stack exchange,提问作者Hasitha Chandula
相关产品推荐
相关产品推荐

