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

异步函数中设置isLogged状态始终返回false的技术求助

用户认证状态更新异常问题

我正在实现用户认证功能,需要从JWT Token中解码用户凭证并跟踪用户登录状态。但异步函数signIn调用setIslogged(true)后,isLogged始终返回false,导致无法渲染用户仪表盘。相关代码如下:

const useAuth = () => {
  const tokenKey = 'authToken';
  const [isLogged, setIslogged] = useState<boolean>(false);
  const [loggedUser, setloggedUser] = useState<authUsers | null>(null);
  const {user, setUser} = useContext(AuthContext);

  const singIn = async function LoginUser(token: string) {
    console.log('calling singin');
    if (isLogged && loggedUser) return;

    console.log('The USer was not logged in');

    try {
      console.log('calling singin try');
      await AsyncStorage.setItem(tokenKey, token);
      console.log('calling singin try setItem with token:', token);
      const tok = await AsyncStorage.getItem(tokenKey);
      console.log('calling singin try getItem with token:', tok);

      if (!token) return;
      console.log('Token Found Trying to decode');
      const decodedUser = convertTokenToUser(token);
      if (!decodedUser) return;
      console.log('Decode Successfull Here ', decodedUser);
      setIslogged(true);
      if (decodedUser) {
        console.log('Setting is logged to true ');
        console.log('User logged in', isLogged);
        console.log('Setting logged user done');
        setloggedUser(decodedUser);
        console.log('User logged in', decodedUser);
        setUser(decodedUser);
      }
    } catch (error) {
      setIslogged(false);
    }
  };

  useLayoutEffect(() => {
    const getTokenAndSignIn = async () => {
      const token = await getToken();
      if (token) {
        singIn(token);
      }
    };
    getTokenAndSignIn();
  }, []);

  return {isLogged, singIn, singOut, getToken, loggedUser};
};

export default useAuth;

问题分析与解决方案

核心问题原因

  1. useState异步更新特性:调用setIslogged(true)后,React不会立刻更新状态,当前函数作用域内的isLogged仍为旧值,所以调用后立刻打印会看到false。
  2. 闭包陷阱:singIn函数在组件初始化时创建,它捕获的isLogged是初始的false值,后续即使状态更新,函数内的isLogged还是旧值,导致if (isLogged && loggedUser) return判断永远不生效,可能重复执行登录逻辑。
  3. useLayoutEffect依赖缺失:原代码中useLayoutEffect的依赖数组为空,只会执行一次,若singIn函数因组件重新渲染而更新,不会重新触发初始化逻辑。

修改后的代码

import { useState, useContext, useLayoutEffect, useEffect, useCallback } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AuthContext, authUsers } from './你的上下文文件路径'; // 替换为实际路径

const useAuth = () => {
  const tokenKey = 'authToken';
  const [isLogged, setIslogged] = useState<boolean>(false);
  const [loggedUser, setloggedUser] = useState<authUsers | null>(null);
  const { user, setUser } = useContext(AuthContext);

  // 用useCallback包裹,确保依赖变化时获取最新状态
  const singIn = useCallback(async (token: string) => {
    console.log('调用singIn');
    if (isLogged && loggedUser) return;

    try {
      await AsyncStorage.setItem(tokenKey, token);
      const storedToken = await AsyncStorage.getItem(tokenKey);
      console.log('存储的token:', storedToken);

      if (!token) return;
      const decodedUser = convertTokenToUser(token);
      if (!decodedUser) return;

      // 更新状态
      setIslogged(true);
      setloggedUser(decodedUser);
      setUser(decodedUser);
      console.log('用户登录成功,用户信息:', decodedUser);
    } catch (error) {
      setIslogged(false);
      console.error('登录失败:', error);
    }
  }, [isLogged, loggedUser, setUser]);

  // 监听isLogged状态变化,验证更新
  useEffect(() => {
    console.log('当前登录状态:', isLogged);
  }, [isLogged]);

  // 初始化时获取token并登录
  useLayoutEffect(() => {
    const getTokenAndSignIn = async () => {
      const token = await AsyncStorage.getItem(tokenKey);
      if (token) {
        await singIn(token);
      }
    };
    getTokenAndSignIn();
  }, [singIn]);

  // 实现退出登录逻辑
  const singOut = async () => {
    await AsyncStorage.removeItem(tokenKey);
    setIslogged(false);
    setloggedUser(null);
    setUser(null);
  };

  // 实现获取token逻辑
  const getToken = async () => {
    return await AsyncStorage.getItem(tokenKey);
  };

  return { isLogged, singIn, singOut, getToken, loggedUser };
};

export default useAuth;

关键修改说明

  • useCallback包裹singIn:确保函数能捕获最新的isLogged和loggedUser状态,避免闭包陷阱。
  • 移除即时打印isLogged:改用useEffect监听isLogged变化,才能看到真实的更新后状态。
  • 补充useLayoutEffect依赖:将singIn加入依赖数组,确保函数更新时重新触发初始化逻辑。
  • 完善缺失函数:补充singOut和getToken的实现,保证功能完整性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 10:45:04