React Native使用SecureStore检测用户登录状态异常问题排查
问题分析与修复方案
核心问题
IsAuth是异步函数,直接调用返回Promise对象(你看到的{"_A": null, "_x": 0, "_y": 0, "_z": null}就是Promise的内部结构),而非预期的布尔值,导致x永远为真(因为对象非空)。UseToken中直接将异步函数getToken()传给useState,导致token状态初始值是Promise,不是实际的token字符串或null,后续传给IsAuth时会引发解析错误。
修复代码
1. 修正UseToken.js:异步初始化token状态
import { useState, useEffect } from 'react'; import * as SecureStore from 'expo-secure-store'; export default function UseToken() { const [token, setToken] = useState(null); // 异步获取token并更新状态 useEffect(() => { const fetchToken = async () => { const tokenString = await SecureStore.getItemAsync("iScore"); // 解析存储的JSON字符串,避免双重序列化 const parsedToken = tokenString ? JSON.parse(tokenString) : null; setToken(parsedToken); }; fetchToken(); }, []); const saveToken = async userToken => { await SecureStore.setItemAsync("iScore", JSON.stringify(userToken)); setToken(userToken); }; return { setToken: saveToken, token }; }
2. 修正Login.js:正确处理异步认证逻辑
import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import UseToken from './UseToken'; import IsAuth from './IsAuth'; export default function Login() { const { token } = UseToken(); const navigate = useNavigate(); const [isAuthenticated, setIsAuthenticated] = useState(false); const [isLoading, setIsLoading] = useState(true); // 加载状态避免误导航 useEffect(() => { const checkAuth = async () => { if (!token) { setIsAuthenticated(false); setIsLoading(false); return; } const authResult = await IsAuth(token); setIsAuthenticated(authResult); setIsLoading(false); }; checkAuth(); }, [token]); // 认证状态确定后再执行导航 useEffect(() => { if (!isLoading && isAuthenticated) { navigate("/countries"); } }, [navigate, isAuthenticated, isLoading]); // 加载中显示占位内容 if (isLoading) { return <div>Loading...</div>; } return ( // 你的登录表单代码 <div>Login Page</div> ); }
3. 优化IsAuth.js:调整判断顺序避免冗余错误
import jwt from 'jsonwebtoken'; import * as SecureStore from 'expo-secure-store'; export default async function IsAuth(token) { // 先判断token是否存在 if (!token) { await SecureStore.deleteItemAsync("iScore"); return false; } try { const decoded = jwt.decode(token); if (!decoded?.exp) { await SecureStore.deleteItemAsync("iScore"); return false; } // 检查token是否过期 if (Math.round(Date.now() / 1000) >= decoded.exp) { await SecureStore.deleteItemAsync("iScore"); return false; } return true; } catch (e) { await SecureStore.deleteItemAsync("iScore"); return false; } }
关键说明
- 异步操作必须配合
useEffect和状态更新,不能直接将Promise赋值给变量或状态初始值。 - 增加
isLoading状态可以避免在认证结果出来前执行导航逻辑,提升用户体验。 - 注意JSON序列化/解析的一致性,避免双重序列化导致token解析失败。
内容的提问来源于stack exchange,提问作者HLT
相关产品推荐
相关产品推荐

