[英]Warning: Can't perform a React state update on an unmounted component after update context and redirect to another page
I am having a problem which needs your helps我有一个需要你帮助的问题
I have a changeProfile
function which will be executed after onClick
in /editpage
我有一个
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);
});
};
context.tsx上下文.tsx
const [userLogin, setUserLogin] = useState({
email: '',
name: '',
....
});
after page redirects to /mypage
, console logs warning error as title and it only logs warning at the first time (if I back to /editpage
and changeProfile
one more time, console logs nothing in /mypage
)页面重定向到
/mypage
后,控制台将警告错误记录为标题,并且仅在第一次记录警告(如果我再次返回/editpage
和changeProfile
,控制台将在/mypage
中不记录任何内容)
I have tried to redirect
after setUserLogin
done as code below but it's not working我尝试在
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]);
Thanks for reading!谢谢阅读!
PS: Problem can be solved with PS:问题可以解决
setTimeout(() => {
router.push('/mypage');
}, 1000);
but its absolutely not a right choice但它绝对不是一个正确的选择
As the warning suggests, because your API code is asynchronous, if you redirect away from the page too fast, the setState may occur after the component has already been unmounted.正如警告所暗示的,由于您的 API 代码是异步的,因此如果您重定向离开页面的速度过快,则可能会在组件已卸载后发生 setState。 What you can do, is use the
callback
argument of setState
(assuming you're calling setState
somewhere in the setUserLogin
function), to redirect after the state update has already been completed.您可以做的是使用
setState
的callback
参数(假设您在setUserLogin
函数的某处调用setState
),在 state 更新完成后重定向。
Edit : You could try adding another state variable to your context to signify that an update has been performed, something like updated: false
and then with your setUserLogin
call:编辑:您可以尝试将另一个 state 变量添加到您的上下文中,以表示已执行更新,例如
updated: false
,然后使用您的setUserLogin
调用:
setUserLogin({
...userLogin,
name: userProfile.name,
updated: true
});
Then you can use the useEffect
hook to check for this condition and then redirect:然后你可以使用
useEffect
钩子来检查这种情况,然后重定向:
useEffect(() => {
if (userLogin.updated) {
router.push('/mypage');
}
})
Then at some point, you would have to reset this variable to false
.然后在某个时候,您必须将此变量重置为
false
。 However, now that I know your setUserLogin
is coming from the AppContext
component, I think the issue is that this component is getting unmounted when it shouldn't be.但是,既然我知道您的
setUserLogin
来自AppContext
组件,我认为问题是该组件在不应该被卸载时被卸载。 Make sure you're rendering this component high enough in the component tree so that the mypage
you redirect to still has this AppContext
mounted确保你在组件树中渲染这个组件足够高,以便你重定向到的
mypage
仍然安装了这个AppContext
Edit 2 : A good approach to prevent this error is by adding a guard to a component class, which keeps track of whether the component is mounted or not.编辑 2 :防止此错误的一个好方法是向组件 class 添加防护,以跟踪组件是否已安装。 Something like this:
像这样的东西:
class AppContext extends Component {
_mounted = False;
componentDidMount() {
this._mounted = true;
}
componentWillUnmount() {
this._mounted = false;
}
...
}
Then, when you call setState
or the update function from useState
, you can first check to see if the component is mounted or not before trying to update:然后,当您从
useState
调用setState
或更新 function 时,您可以先检查组件是否已安装,然后再尝试更新:
if (AppContext._mounted) {
setUserLogin({
...userLogin,
name: userProfile.name,
updated: true
});
}
However, in your case, this may prevent the information from being updated as you expect, since the component is unmounting, which is why I think the issue lies with why the component is unmounting但是,在您的情况下,这可能会阻止信息按您的预期更新,因为组件正在卸载,这就是为什么我认为问题在于组件卸载的原因
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.