You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AsyncStorage实现登出时触发Invalid hook call警告的问题

解决React登出功能的无效钩子调用警告

问题描述

实现登出功能时用AsyncStorage做数据持久化,功能可正常运行,但触发警告:

LOG 移除项时出错:错误:无效的钩子调用。钩子只能在函数组件的主体内部调用。可能由以下原因导致:

  1. React与渲染器(如React DOM)版本不匹配
  2. 违反了钩子规则
  3. 应用中存在多个React副本。

原代码片段:

const login = (userEmail, userPasswd) => {
    try {
        setLoading(true);
        axios.post(`${BASE_URL}/account/login`,
            { userEmail, userPasswd }
        ).then(res => {
            let userInfo = res.data;
            setUserInfo(userInfo)
            AsyncStorage.setItem('userInfo', JSON.stringify(userInfo))
            setLoading(false)
        }).catch(e => {
            if (userEmail !== userEmail && userPasswd !== userPasswd) {
                setError(`login error ${e.res}`);
                setLoading(false)
                Toast.show('Email or Password not match.');
            }
        })
    } catch (error) {
        setLoading(false)
        console.error(error)
        Toast.show('Email or Password not match.');
    }
}

const logout = async () => {
    try {
        await AsyncStorage.removeItem('userInfo');
        setUserInfo({})
        useNavigate('Login')
    } catch (error) {
        console.log(`Error removing item: ${error}`);
    }
};

问题根源

警告的核心原因是在普通异步函数logout内部调用了useNavigate钩子。React钩子规则明确要求:钩子只能在函数组件的顶层作用域,或者自定义钩子的顶层作用域中调用,不能嵌套在普通函数、条件判断、循环等代码块里。

解决方案

1. 修正logout函数的钩子调用方式

先在组件的顶层作用域调用useNavigate获取导航函数,再在logout中使用这个函数:

// 必须在组件主体的顶层(所有函数外部)调用useNavigate
const navigate = useNavigate();

const logout = async () => {
    try {
        await AsyncStorage.removeItem('userInfo');
        setUserInfo({});
        // 使用提前获取的navigate函数跳转页面
        navigate('/Login'); // 路径格式根据你的路由配置调整,通常带斜杠
    } catch (error) {
        console.log(`Error removing item: ${error}`);
    }
};

2. 额外优化建议(可选)

  • 原login函数中的catch块判断逻辑userEmail !== userEmail && userPasswd !== userPasswd永远为false,无法触发错误提示。建议改为根据axios返回的错误信息或状态码判断,比如:
    .catch(e => {
        setLoading(false);
        if (e.response?.status === 401) {
            Toast.show('Email or Password not match.');
        } else {
            setError(`Login error: ${e.message}`);
            Toast.show('Login failed, please try again later.');
        }
    })
    
  • 原login函数外层的try/catch无法捕获axios异步请求的错误(因为axios的错误已经被.catch处理),可以移除外层try/catch简化代码。

内容的提问来源于stack exchange,提问作者Chingtham Khuman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:57:59