You need to enable JavaScript to run this app. React使用useContext更新登录状态时出现未挂载组件状态更新警告如何解决
优惠活动
大模型
产品
解决方案
定价
更多

React使用useContext更新登录状态时出现未挂载组件状态更新警告如何解决

警告产生原因

Can't perfom a React state update on an unamounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in useEffect cleanup function

这个警告的核心触发逻辑是:你在登录请求成功后先执行了setUser(true)更新全局Context状态,App.js监听到user变为true后,直接将包含Login组件的AuthStackScreen卸载,切换为登录后的BuyerDashboardStackScreens。但此时Login组件的请求回调里还有setName('')、setPassword('')、setPress(false)等针对Login内部状态的更新操作,对已经卸载的组件执行状态更新就会抛出这个警告。

解决方法

优先选择改动最小的方案即可:

方案1:调整状态更新顺序(最简便)

把Login组件内部状态的更新逻辑放到全局状态更新之前执行,确保内部状态更新完成后再触发路由切换卸载组件,修改后Login.js的成功分支逻辑如下:

if (response.data.Success == true) {
    const token = response.data.token.toString();
    const super_user_status = response.data.super_user_status.toString();
    const isLoggedIn = "1"
    console.log('Logged In and set Storgae')
    await AsyncStorage.multiSet([['isLoggedIn',isLoggedIn],['token', token], ['super_user_status', super_user_status]])
    // 先更新Login组件内部状态
    setName('')
    setPassword('')
    setPress(false)
    // 最后更新全局状态,触发路由切换
    setUser(true) 
}

同时记得给失败分支、catch分支里的内部状态更新也做对应顺序调整,所有内部状态更新都放在全局状态更新之前。

方案2:增加组件挂载标记

如果存在组件可能在请求返回前就被卸载的场景,可以加挂载标记判断组件状态,仅在组件未卸载时执行状态更新:

import { useRef, useEffect } from 'react'

const Login = ({ navigation }) => {
    // 标记组件是否处于挂载状态
    const isMounted = useRef(true)
    // 组件卸载时修改标记
    useEffect(() => () => isMounted.current = false, [])

    const login = async () => {
        // 原有逻辑不变,所有状态更新前先判断挂载状态
        await axios(...).then(async function (response) {
            if (response.data.Success == true) {
                // 原有存储逻辑不变
                await AsyncStorage.multiSet(...)
                if(isMounted.current) {
                    setUser(true)
                    setName('')
                    setPassword('')
                    setPress(false)
                }
            } else if (response.data.Success == false) {
                if(isMounted.current) {
                    setPress(false)
                    setErrorMsg(response.data.Error)
                    setName('')
                    setPassword('')
                }
            }
        }).catch(function (response) {
            if(isMounted.current) {
                setErrorMsg('Server Error 404');
                setPress(false)
            }
        })
    }
}

方案3:请求自动取消

用axios自带的CancelToken在组件卸载时直接取消未完成的请求,不会进入后续的回调逻辑:

import { CancelToken } from 'axios'
import { useEffect } from 'react'

const Login = ({ navigation }) => {
    let cancelRequest
    // 组件卸载时取消未完成的登录请求
    useEffect(() => () => cancelRequest?.(), [])

    const login = async () => {
        // 原有逻辑不变
        await axios({
            method: 'POST',
            url: api + 'login/',
            data: login_Credentials,
            headers: { 'Content-Type': 'multipart/form-data' },
            // 注入取消令牌
            cancelToken: new CancelToken(c => cancelRequest = c)
        }).then(/* 原有回调逻辑不变 */)
    }
}

内容的提问来源于stack exchange,提问作者Adil Ijaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 17:24:07