React使用Context实现登录跳转时报未挂载组件状态更新错误如何处理
错误原因
该警告由已卸载组件的状态更新触发,执行流程如下:
- 登录接口请求成功后进入回调函数,首先调用
Auth.logIn()更新AuthProvider的全局状态,isAuthenticated变为true - 路由层
ProtectedLogin组件检测到登录态变更,直接触发重定向到/home,LoginForm、LoginPage组件被立即卸载 - 回调后续执行
setRedirect(true)更新LoginForm的本地状态,此时组件已被卸载,触发警告
修复方案
方案1(最优):移除冗余的重定向逻辑
你的路由层已经配置了登录态校验逻辑:已登录用户访问登录页会自动跳转到首页,不需要在LoginForm内单独维护redirect状态控制跳转,直接删除冗余代码即可。
修改后的login-form.component.tsx核心代码:
const LoginForm = () => { const Auth = React.useContext(AuthContext); return ( <Formik initialValues={{ email: "", password: "" }} onSubmit={(formValues: FormikValues) => { ApiService.post("user/authenticate", formValues) .then((res: any) => { Auth.logIn({token: res.token}); Auth.initTokenChecking(); // 移除setRedirect调用,路由层会自动处理跳转 }) .catch(() => console.log('error')); }} validationSchema={Yup.object().shape({ email: Yup.string(), password: Yup.string() })} > {/* 其余Formik渲染逻辑保持不变 */} </Formik> ); }; export default LoginForm;
方案2(可选):添加组件挂载状态检测
如果需要保留LoginForm内的重定向逻辑,可以添加挂载状态标记,避免更新已卸载组件的状态:
const LoginForm = () => { const [redirect, setRedirect] = useState(false); const Auth = React.useContext(AuthContext); const isMounted = useRef(true); useEffect(() => { return () => { isMounted.current = false; } }, []); if (redirect) { return <Redirect to="/home" />; } return ( <Formik initialValues={{ email: "", password: "" }} onSubmit={(formValues: FormikValues) => { ApiService.post("user/authenticate", formValues) .then((res: any) => { Auth.logIn({token: res.token}); Auth.initTokenChecking(); if (isMounted.current) { setRedirect(true); } }) .catch(() => console.log('error')); }} // 其余配置保持不变 > {/* 其余渲染逻辑保持不变 */} </Formik> ); };
附加优化:避免重复创建定时器
当前initTokenChecking方法每次登录都会新建定时器,重复登录会导致多个定时器同时运行,同时未处理token不存在时的解码报错,建议修改为:
initTokenChecking = () => { // 先清理已有定时器,避免重复创建 if (this._interval) { clearInterval(this._interval); } this._interval = setInterval(() => { if (!localStorage.getItem("token")) { this.logOut(); return; // 无token直接返回,避免后续解码报错 } const token = JSON.parse(localStorage.getItem("token")); console.log(jwt_decode(token)); if (jwt_decode(token).exp < Date.now() / 1000) { this.logOut(); } }, 2 * 60 * 1000); };
内容的提问来源于stack exchange,提问作者K.W.
相关产品推荐
相关产品推荐

