React Native:useFocusEffect无法获取更新后的remember状态值
问题分析与解决
核心问题是闭包陷阱:useCallback的依赖数组为空,导致它包裹的卸载回调始终捕获组件初始渲染时的remember值(也就是undefined),后续remember状态更新后,回调不会重新生成,自然拿不到最新值。
另外还有几个次要问题需要修复:
useFocusEffect里的AsyncStorage.getItem没有加await,会导致currentUser是Promise对象而非解析后的数据Toggle的onToggle回调里重复调用setRemember,会引发状态更新异常useState未设置初始值,初始状态为undefined容易引发判断错误
修复步骤
- 添加依赖到useCallback:把
remember加入useCallback的依赖数组,确保状态更新时回调能捕获最新值 - 补全await关键字:
AsyncStorage.getItem是异步操作,必须加await才能拿到正确数据 - 简化状态更新逻辑:合并
onToggle里的重复操作,直接在回调中切换状态并处理存储逻辑 - 设置useState初始值:给
remember设置默认值false,避免初始状态为undefined
修改后的完整代码
import React, { useState, useEffect, useCallback } from 'react'; import { SafeAreaView, AsyncStorage } from 'react-native'; import { useFocusEffect } from '@react-navigation/native'; import Toggle from './Toggle'; // 假设Toggle组件路径正确 const rememberMe = ({ navigation }) => { // 给useState设置初始值false const [remember, setRemember] = useState(false); useEffect(() => { getUserEmailAndPassword(); }, []); const getUserEmailAndPassword = async () => { try { const loginSaved = await AsyncStorage.getItem("userLoginDetails"); const currentUser = JSON.parse(loginSaved); // 直接设置状态,简化判断 setRemember(currentUser?.state === true); } catch (error) { console.error('获取登录信息失败:', error); } }; useFocusEffect( useCallback(() => { return () => { // 现在能拿到最新的remember值 if (remember === true) { forgetUser(); } else { saveUserLoginDetails(); } }; // 加入remember到依赖数组 }, [remember]) ); const rememberUser = async (email, password, state) => { const userLoginDetails = { userEmail: email, userPassword: password, state: state, }; try { await AsyncStorage.setItem( "userLoginDetails", JSON.stringify(userLoginDetails) ); } catch (error) { console.error('保存登录信息失败:', error); } }; // 提取保存逻辑为单独函数,添加await const saveUserLoginDetails = async () => { try { const loginSaved = await AsyncStorage.getItem("userLoginDetails"); const currentUser = JSON.parse(loginSaved); if (currentUser?.userEmail && currentUser?.userPassword) { rememberUser( currentUser.userEmail, currentUser.userPassword, true ); } } catch (error) { console.error('处理登录信息失败:', error); } }; const forgetUser = async () => { try { await AsyncStorage.removeItem("userLoginDetails"); } catch (error) { console.error('清除登录信息失败:', error); } }; return ( <SafeAreaView style={styles.securityContainer} edges={["right", "top", "left"]} > <Toggle isOn={remember} onToggle={() => { // 直接切换状态,无需重复调用setRemember const newState = !remember; setRemember(newState); }} /> </SafeAreaView> ); }; export default rememberMe;
内容的提问来源于stack exchange,提问作者Manish Kumar
相关产品推荐
相关产品推荐

