React Native AsyncStorage结合Django后端登录/登出问题求解
React Native AsyncStorage登录/登出问题修复方案
问题1:未登录读取返回Promise对象
你直接调用ch()异步函数时没加await,拿到的自然是Promise对象;而且在组件渲染阶段直接执行异步判断,这不符合React组件的生命周期逻辑。
修复方法
用useState存储登录状态和用户名,通过useEffect在组件挂载时执行异步读取操作:
问题2:登出后关闭应用仍自动登录
原登出逻辑可能存在异步操作未完成就跳转的情况,且登录页的判断逻辑只在初始化时执行一次,没有响应存储变化。
修复方法
确保登出时等待AsyncStorage.removeItem执行完成后再跳转,同时重置导航栈避免用户返回首页;登录页通过useEffect在每次挂载时重新检查存储状态。
完整修改后的代码
login.js
import { StatusBar } from 'expo-status-bar' import React, { useState, useEffect } from 'react' import { TextInput } from 'react-native-gesture-handler'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { StyleSheet, Text, View, Button, Pressable, ScrollView } from 'react-native'; export default function Login(props) { const message = props.navigation.getParam('message', null) const [username, setUsername] = useState("") const [password, setPassword] = useState("") const [isLoggedIn, setIsLoggedIn] = useState(false) const [storedUser, setStoredUser] = useState(null) const setStringValue = async (value) => { try { await AsyncStorage.setItem('@userauthkey', value) } catch (e) { console.log(e) } } const getData = async () => { try { const value = await AsyncStorage.getItem('@userauthkey') return value !== null ? value : null } catch (e) { console.log(e) return null } } // 组件挂载时检查登录状态 useEffect(() => { const checkAuthStatus = async () => { const user = await getData() if (user) { setStoredUser(user) setIsLoggedIn(true) props.navigation.navigate('Home', { user }) } else { setIsLoggedIn(false) } } checkAuthStatus() }, [props.navigation]) const log = () => { fetch(`http://192.168.5.223:8000/home/login/`, { method: 'POST', headers: { "Content-Type": 'application/json' }, body: JSON.stringify({ username, password }), }) .then(res => res.json()) .then(async (res) => { console.log(res) if (res.valid === true) { await setStringValue(username) if (res.set === true) { props.navigation.navigate("Home", { user: username }) } else { props.navigation.navigate("Profile", { user: username }) } } else { props.navigation.navigate("Login", { message: "username/password are incorrect" }) } }) .catch(error => console.log(error)) } const sign = () => { props.navigation.navigate("Signup") } return ( <View style={styles.container} > <ScrollView style={styles.scroll} > <View style={styles.main}> <Text style={styles.error}> {message} </Text> <Text style={styles.label}>Username:</Text> <TextInput style={styles.input} placeholder="Username" onChangeText={setUsername} value={username} autoCapitalize={'none'} /> <Text style={styles.label}> Password: </Text> <TextInput style={styles.input} placeholder="Password" onChangeText={setPassword} value={password} secureTextEntry={true} autoCapitalize={'none'} /> <Button onPress={log} title="Login" /> </View> </ScrollView> <View style={styles.footer} > <Button onPress={sign} title="Don't have an account? Sign up now" /> </View> <StatusBar style="auto" /> </View> ) } Login.navigationOptions = screenProps => ({ headerLeft: () => null, gestureEnabled: false, headerStyle: { backgroundColor: 'black' }, headerTintColor: 'white', }) const styles = StyleSheet.create({ error: { textAlign: 'center', color: 'red', }, main: { paddingTop: 145, paddingHorizontal: 5, }, container: { flex: 1, backgroundColor: 'black', }, scroll: { backgroundColor:'#000' }, footer: { borderTopColor: '#fff', padding:35, }, label: { fontSize: 24, color: "white", padding: 10, }, input: { fontSize: 24, backgroundColor: "white", padding: 10, margin: 10, borderRadius: 5, }, });
home.js
import { StatusBar } from 'expo-status-bar' import { StyleSheet, Text, View, Pressable, ScrollView } from 'react-native'; import React, { useState, useEffect } from 'react' import AsyncStorage from '@react-native-async-storage/async-storage'; import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; import { faUser } from '@fortawesome/free-regular-svg-icons'; import { faComment } from '@fortawesome/free-regular-svg-icons'; export default function Home(props) { const [current, setCurrent] = useState("profile") const user = props.navigation.getParam("user", null) const curr = (cur) => { setCurrent(cur) } const gprof = (user) => { fetch(`http://192.168.5.223:8000/home/checkprofile/`,{ method: 'POST', headers: { "Content-Type": 'application/json', }, body: JSON.stringify({user}), }) .then(res => res.json()) .then(res => { console.log(res.profile) console.log(res.sets) if (res.sets === false){ props.navigation.navigate('Profile') } }) .catch(error => console.log(error)) } const logout = async () => { try { await AsyncStorage.removeItem('@userauthkey') // 重置导航栈,避免用户返回首页 props.navigation.reset({ index: 0, routes: [{ name: 'Login' }], }) } catch(e){ console.log(e) } } if(current === "profile"){ return ( <View style={styles.container}> <ScrollView style={styles.scroll} > <Text> profile {user} </Text> <Pressable onPress={logout}> <Text>Logout</Text> </Pressable> </ScrollView> <View style={styles.footer}> <Pressable onPress={() => curr('profile')}> <FontAwesomeIcon icon={faUser} style={{color: 'white'}}/> </Pressable> <Pressable onPress={() => curr('messanger')}> <FontAwesomeIcon icon={faComment} style={{color: 'white', marginLeft: 20}} /> </Pressable> </View> <StatusBar style="auto"/> </View> ) } else if(current === "posts"){ return ( <View style={styles.container}> <ScrollView style={styles.scroll} > <Text> posts {user} </Text> </ScrollView> <View style={styles.footer}> </View> <StatusBar style="auto"/> </View> ) } else if (current === "messanger"){ return ( <View style={styles.container}> <ScrollView style={styles.scroll} > <Text> messanger {user} </Text> </ScrollView> <View style={styles.footer}> <Pressable onPress={() => curr('profile')}> <FontAwesomeIcon icon={faUser} style={{color: 'white'}}/> </Pressable> <Pressable onPress={() => curr('messanger')}> <FontAwesomeIcon icon={faComment} style={{color: 'white', marginLeft: 20}} /> </Pressable> </View> <StatusBar style="auto"/> </View> ) } } Home.navigationOptions = screenProps => ({ headerLeft: () => null, gestureEnabled: false, headerStyle: { backgroundColor: 'black' }, headerTintColor: 'white', }) const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#999', }, scroll: { backgroundColor:'#999' }, footer: { borderTopColor: '#fff', padding:35, flexDirection: 'row', }, label: { fontSize: 24, color: "white", padding: 10, }, input: { fontSize: 24, backgroundColor: "white", padding: 10, margin: 10, borderRadius: 5, }, });
内容的提问来源于stack exchange,提问作者Itay Lador
相关产品推荐
相关产品推荐

