[英]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.