React中useHistory调用push触发已卸载组件状态更新警告如何解决
问题根因
你触发警告的核心原因是:执行history.push完成路由跳转后,当前Signin组件会被直接卸载,但你在跳转之后还执行了setFormData操作修改组件状态,对已卸载的组件更新状态就会触发该内存泄漏警告。问题主要出现在登录请求成功的回调逻辑中。
修复方案
方案1:调整逻辑执行顺序(最简单,适合你的场景)
把状态更新操作放到路由跳转之前,跳转后不再执行任何组件状态修改即可:
signin(data) //! return response .then(response => { setAuthentication(response.data.token, response.data.user); // 先更新状态,再执行跳转 setFormData({ ...formData, loading: false, }); // 最后跳转,跳转后无其他操作 if (isAuthenticated() && isAuthenticated().role === 1) { history.push('/admin/dashboard'); } else { history.push('/user/dashboard'); } })
请求失败的catch逻辑不需要修改,因为失败时不会触发跳转,组件仍处于挂载状态,更新状态是合法的。
方案2:通用挂载标记方案(适合多异步逻辑的复杂场景)
如果你的业务有更多异步逻辑不好调整执行顺序,可以用ref标记组件挂载状态,所有状态更新前先判断组件是否仍处于挂载状态:
const Signin = () => { let history = useHistory(); // 新增挂载状态标记 const isMounted = useRef(true); // 组件卸载时更新标记 useEffect(() => { return () => { isMounted.current = false; } }, []); // 其余代码不变,修改handleSubmit中的回调逻辑,所有setFormData前加判断 const handleSubmit = (e) => { // 原有验证逻辑不变 signin(data) .then(response => { setAuthentication(response.data.token, response.data.user); // 仅组件挂载时更新状态 if (isMounted.current) { setFormData({ ...formData, loading: false, }); } if (isAuthenticated() && isAuthenticated().role === 1) { history.push('/admin/dashboard'); } else { history.push('/user/dashboard'); } }) .catch(error => { // 仅组件挂载时更新状态 if (isMounted.current) { setFormData({ ...formData, loading: false, errorMsg: error.response.data.errorMessage }); } }); } // 其余代码不变 }
额外优化点
你当前用于校验登录状态的useEffect依赖为history,如果你的isAuthenticated方法是从本地存储读取身份信息,没有依赖组件状态,可以将依赖改为空数组,避免不必要的重复执行:
useEffect(() => { const userInfo = isAuthenticated(); if (userInfo?.role === 1) { history.push('/admin/dashboard'); } else if (userInfo?.role === 0) { history.push('/user/dashboard'); } }, []);
内容的提问来源于stack exchange,提问作者victhangnguyen
相关产品推荐
相关产品推荐

