簡體   English   中英

警告:更新上下文並重定向到另一個頁面后,無法在未安裝的組件上執行 React state 更新

[英]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后,控制台將警告錯誤記錄為標題,並且僅在第一次記錄警告(如果我再次返回/editpagechangeProfile ,控制台將在/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。 您可以做的是使用setStatecallback參數(假設您在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM