繁体   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