异步函数中设置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;
问题分析与解决方案
核心问题原因
useState异步更新特性:调用setIslogged(true)后,React不会立刻更新状态,当前函数作用域内的isLogged仍为旧值,所以调用后立刻打印会看到false。- 闭包陷阱:
singIn函数在组件初始化时创建,它捕获的isLogged是初始的false值,后续即使状态更新,函数内的isLogged还是旧值,导致if (isLogged && loggedUser) return判断永远不生效,可能重复执行登录逻辑。 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
相关产品推荐
相关产品推荐

