[英]Warning: Can't perform a React state update on an unmounted component after update context and redirect to another page
我有一个需要你帮助的问题
我有一个changeProfile
function 将在/editpage
onClick
的 onClick 之后执行
const appContext = useContext(AppContext);
const [userLogin, setUserLogin] = appContext.userLogin;
const [userProfile, setUserProfile] = useState<UserProfile>({
name: userLogin.name,
....
});
const changeProfile = e => {
e.preventDefault();
post(API)
.then(() => {
setUserLogin({
...userLogin,
name: userProfile.name,
});
router.push('/mypage');
})
.catch(error => {
setEditError(error[0]);
window.scrollTo(0, 0);
});
};
上下文.tsx
const [userLogin, setUserLogin] = useState({
email: '',
name: '',
....
});
页面重定向到/mypage
后,控制台将警告错误记录为标题,并且仅在第一次记录警告(如果我再次返回/editpage
和changeProfile
,控制台将在/mypage
中不记录任何内容)
我尝试在setUserLogin
完成后redirect
,但它不起作用
const changeProfile = e => {
e.preventDefault();
post(API)
.then(() => {
setUserLogin({
...userLogin,
name: userProfile.name,
});
})
.catch(error => {
setEditError(error[0]);
window.scrollTo(0, 0);
});
};
const firstUpdate = useRef(true);
useLayoutEffect(() => {
if (firstUpdate.current) {
firstUpdate.current = false;
return;
}
console.log(userLogin); //already updated
router.push('/mypage');
}, [userLogin]);
谢谢阅读!
PS:问题可以解决
setTimeout(() => {
router.push('/mypage');
}, 1000);
但它绝对不是一个正确的选择
正如警告所暗示的,由于您的 API 代码是异步的,因此如果您重定向离开页面的速度过快,则可能会在组件已卸载后发生 setState。 您可以做的是使用setState
的callback
参数(假设您在setUserLogin
函数的某处调用setState
),在 state 更新完成后重定向。
编辑:您可以尝试将另一个 state 变量添加到您的上下文中,以表示已执行更新,例如updated: false
,然后使用您的setUserLogin
调用:
setUserLogin({
...userLogin,
name: userProfile.name,
updated: true
});
然后你可以使用useEffect
钩子来检查这种情况,然后重定向:
useEffect(() => {
if (userLogin.updated) {
router.push('/mypage');
}
})
然后在某个时候,您必须将此变量重置为false
。 但是,既然我知道您的setUserLogin
来自AppContext
组件,我认为问题是该组件在不应该被卸载时被卸载。 确保你在组件树中渲染这个组件足够高,以便你重定向到的mypage
仍然安装了这个AppContext
编辑 2 :防止此错误的一个好方法是向组件 class 添加防护,以跟踪组件是否已安装。 像这样的东西:
class AppContext extends Component {
_mounted = False;
componentDidMount() {
this._mounted = true;
}
componentWillUnmount() {
this._mounted = false;
}
...
}
然后,当您从useState
调用setState
或更新 function 时,您可以先检查组件是否已安装,然后再尝试更新:
if (AppContext._mounted) {
setUserLogin({
...userLogin,
name: userProfile.name,
updated: true
});
}
但是,在您的情况下,这可能会阻止信息按您的预期更新,因为组件正在卸载,这就是为什么我认为问题在于组件卸载的原因
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.