I am having a problem which needs your helps
I have a changeProfile
function which will be executed after onClick
in /editpage
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
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
)
I have tried to redirect
after setUserLogin
done as code below but it's not working
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
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. 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.
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:
setUserLogin({
...userLogin,
name: userProfile.name,
updated: true
});
Then you can use the useEffect
hook to check for this condition and then redirect:
useEffect(() => {
if (userLogin.updated) {
router.push('/mypage');
}
})
Then at some point, you would have to reset this variable to 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. 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
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. 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:
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.