React Native使用AuthContext登出时报已卸载组件无法更新状态错误如何解决
问题根因
- 触发
signOut异步方法后,方法内部会执行状态清空、路由跳转逻辑,会先将当前持有登出按钮的页面/相关关联页面卸载,而异步任务后续的回调、状态更新操作仍在执行,尝试给已经卸载的组件赋值状态,就会触发该警告 - 偶发是因为异步执行的时序不固定,有时候状态更新在页面卸载前完成,就不会触发报错
解决方案
1. 调整signOut方法内部执行顺序
找到AuthContext Provider中定义signOut的位置,先完成状态更新操作,再执行路由跳转,避免页面提前卸载后再触发状态更新:
// AuthContext Provider 所在文件 const AuthProvider = ({children}) => { const [user, setUser] = useState(null) const signOut = async () => { try { // 第一步:执行登出接口请求、本地用户缓存清理逻辑 await clearUserCache() // 第二步:更新全局用户状态 setUser(null) // 第三步:最后再执行路由跳转,销毁当前页面 navigation.replace('Login') } catch (e) { console.log('登出失败', e) } } return <AuthContext.Provider value={{user, signOut}}>{children}</AuthContext.Provider> }
2. 给登出操作加防重逻辑
避免用户短时间多次点击登出按钮,导致重复执行signOut逻辑触发多次状态更新:
// 登出按钮所在页面 const [isLoggingOut, setIsLoggingOut] = useState(false) const { signOut } = React.useContext(AuthContext) const handleLogout = async () => { if (isLoggingOut) return setIsLoggingOut(true) try { await signOut() } finally { setIsLoggingOut(false) } } <TouchableOpacity onPress={handleLogout} disabled={isLoggingOut} > <Text>logout</Text> </TouchableOpacity>
3. 通用挂载状态判断方案
如果有零散的异步状态更新不好逐个调整,可以引入挂载状态判断,状态更新前先校验组件是否还处于挂载状态:
// 自定义公共hook,判断组件是否挂载 const useIsMounted = () => { const isMounted = React.useRef(false) React.useEffect(() => { isMounted.current = true return () => { isMounted.current = false } }, []) return isMounted } // 任意组件内使用 const isMounted = useIsMounted() // 异步操作执行完成后,更新状态前先判断 if (isMounted.current) { setYourState(newValue) }
4. 排查路由跳转逻辑
确认登出时的路由跳转使用的是replace/reset这类会销毁当前页面栈的方法,不要使用push,避免登出前的页面残留在页面栈中被误触发状态更新。
内容的提问来源于stack exchange,提问作者S. N
相关产品推荐
相关产品推荐

