React Native登录成功后无法跳转至Home页面问题求助
React Native登录成功后无法跳转Home页面的问题排查与修复
问题根源
- 状态作用域不匹配:StackNavigation组件内的
isLogin状态控制页面切换,但Authorization组件内的isLogin是局部状态,修改它无法影响上层导航组件的状态。 - 导航配置冗余:StackBegin组件中,每个
<Stack.Screen>后额外手动渲染对应组件,导致组件重复实例化,干扰导航逻辑。 - 缺少状态持久化:未处理APP重启后的登录状态恢复,且登录成功后未通知上层导航组件更新状态。
修复步骤
1. 统一登录状态管理
将登录状态提升至StackNavigation组件,通过回调函数让Authorization组件能修改全局状态。
2. 修复导航配置
移除StackBegin中每个<Stack.Screen>后手动渲染的组件,避免重复实例化。
3. 添加状态持久化逻辑
在StackNavigation中通过useEffect读取本地存储的token,初始化登录状态。
4. 调整Authorization登录逻辑
移除Authorization内部的isLogin状态,调用上层传递的回调更新全局登录状态。
修改后的StackNavigation.js
import { createNativeStackNavigator } from '@react-navigation/native-stack' import React, { useState, useEffect } from 'react' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import Startup_screen from '../screens/Begin/Startup_screen'; import Authorization from '../screens/Begin/Authorization'; import Home from '../screens/Main/HomeTab/Home'; import { COLOR, ICON } from '../constants/Theme'; import { appStyle, windowHeight } from '../constants/AppStyle'; import Registration from '../screens/Begin/Registration'; import MyorderCurrent from '../screens/Main/HistoryTab/MyorderCurrent'; import MyorderHistory from '../screens/Main/HistoryTab/MyorderHistory'; import { Image, Text, View } from 'react-native'; import Account from '../screens/Main/ProfileTab/Account'; import Forgot_password from '../screens/Begin/Forgot_password'; import MyCart from '../screens/Main/HomeTab/MyCart'; import UpdateAccount from '../screens/Main/ProfileTab/UpdateAccount'; import Reward from '../screens/Main/ProfileTab/Reward'; import OrderDetail from '../screens/Main/HomeTab/OrderDetail'; import AsyncStorage from '@react-native-async-storage/async-storage'; const Stack = createNativeStackNavigator(); const Tab = createBottomTabNavigator(); const StackBegin = ({ onLoginSuccess }) => { return ( <Stack.Navigator initialRouteName="Start" screenOptions={{ headerShown: false }}> <Stack.Screen name='Start' component={Startup_screen} /> <Stack.Screen name='Authorization'> {(props) => <Authorization {...props} onLoginSuccess={onLoginSuccess} />} </Stack.Screen> <Stack.Screen name='Registration' component={Registration} /> <Stack.Screen name='ForgotPassword' component={Forgot_password} /> </Stack.Navigator> ) }; const StackHome = () => { return ( <Stack.Navigator screenOptions={{ headerShown: false }}> <Stack.Screen name="Home" component={Home}></Stack.Screen> <Stack.Screen name="MyCart" component={MyCart}></Stack.Screen> <Stack.Screen name="OrderDetail" component={OrderDetail} /> </Stack.Navigator> ); }; const StackHistory = () => { return ( <Stack.Navigator screenOptions={{ headerShown: false }}> <Stack.Screen name="MyorderCurrent" component={MyorderCurrent}></Stack.Screen> <Stack.Screen name="MyorderHistory" component={MyorderHistory}></Stack.Screen> </Stack.Navigator> ); }; const StackProfile = () => { return ( <Stack.Navigator screenOptions={{ headerShown: false }}> <Stack.Screen name="Account" component={Account}></Stack.Screen> <Stack.Screen name="UpdateAccount" component={UpdateAccount}></Stack.Screen> <Stack.Screen name="Reward" component={Reward}></Stack.Screen> </Stack.Navigator> ) }; const Main = ({ name }) => { return ( <Tab.Navigator initialRouteName="StackHome" screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => { let iconName, label; if (route.name === 'StackHome') { iconName = focused ? ICON.HomeFocus : ICON.Home; label = "Trang chủ"; } else if (route.name === 'StackHistory') { iconName = focused ? ICON.HistoryFocus : ICON.History; label = "Lịch sử"; } else if (route.name === 'StackProfile') { iconName = focused ? ICON.AccountFocus : ICON.Account; label = "Hồ sơ"; } return ( <View style={{ flex: 1, alignItems: 'center', marginTop: 10, }}> <View> <Image source={iconName} style={{ width: 26, height: 26, resizeMode: 'stretch', tintColor: focused ? COLOR.primary : COLOR.grayText, }} /> </View> <Text style={{ fontSize: 10, fontWeight: 600, marginTop: 4, color: focused ? COLOR.primary : COLOR.grayText, }}> {label} </Text> </View> ); }, tabBarHideOnKeyboard: true, headerShown: false, tabBarShowLabel: false, tabBarStyle: { height: windowHeight * 0.075, position: 'absolute', backgroundColor: COLOR.background, }, })} > <Tab.Screen name="StackHome" component={StackHome} initialParams={{ name }} /> <Tab.Screen name="StackHistory" component={StackHistory} /> <Tab.Screen name="StackProfile" component={StackProfile} /> </Tab.Navigator> ) }; const StackNavigation = () => { const [isLogin, setIsLogin] = useState(false); // 初始化时读取本地token,恢复登录状态 useEffect(() => { const checkLoginStatus = async () => { const token = await AsyncStorage.getItem('userToken'); if (token) { setIsLogin(true); } }; checkLoginStatus(); }, []); // 处理登录成功的回调 const handleLoginSuccess = () => { setIsLogin(true); }; return ( <> {isLogin ? <Main /> : <StackBegin onLoginSuccess={handleLoginSuccess} />} </> ) } export default StackNavigation;
修改后的Authorization.js
import React, { useState } from 'react'; import { useNavigation } from '@react-navigation/native'; import { SafeAreaView, TextInput, TouchableOpacity, Alert, Text, View } from 'react-native'; import FastImage from 'react-native-fast-image'; import axios from 'axios'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { COLOR, ICON } from '../constants/Theme'; import { appStyle, windowHeight, windowWidth } from '../constants/AppStyle'; import AppButton from '../components/AppButton'; const Authorization = ({ onLoginSuccess }) => { const navigation = useNavigation(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleLogin = async () => { try { const response = await axios.post('http://10.0.2.2:3000/users/login', { email: email, password: password }); console.log('Server response:', response.data); if (response.data && response.data.token) { await AsyncStorage.setItem('userToken', response.data.token); Alert.alert('Login successful'); // 调用上层回调更新全局登录状态 onLoginSuccess(); } else { Alert.alert('Login failed', 'Token not found in server response'); } } catch (error) { console.log('Login error:', error); if (error.response && error.response.data) { Alert.alert('Login failed', error.response.data.message); } else { Alert.alert('Login failed', 'An error occurred during login.'); } } }; const handleSignUp = () => { navigation.navigate('Registration'); }; const handleForgot = () => { navigation.navigate('ForgotPassword'); }; return ( <SafeAreaView style={appStyle.container}> <TouchableOpacity onPress={() => navigation.goBack()}> <FastImage resizeMode="stretch" source={ICON.Back} style={appStyle.icon} /> </TouchableOpacity> <View style={{ marginTop: windowHeight * 0.06, marginBottom: windowHeight * 0.04 }}> <Text style={appStyle.text24}>Sign in</Text> <Text style={[appStyle.text16, { color: COLOR.lightText, marginTop: 27 }]}>Welcome back</Text> </View> {/* INPUT EMAIL */} <View style={[styles.viewRow]}> <View style={styles.rowbetween}> <FastImage tintColor={COLOR.primary} resizeMode="stretch" source={ICON.Mail} style={[appStyle.icon, { width: 26 }]} /> <Text style={{ fontSize: 35, color: COLOR.lightText, fontWeight: '200' }}>|</Text> </View> <TextInput style={{ marginLeft: 25 }} placeholder="Email address" placeholderTextColor='#C1C7D0' fontSize={16} value={email} onChangeText={setEmail} /> </View> {/* INPUT PASSWORD */} <View style={[styles.viewRow]}> <View style={styles.rowbetween}> <FastImage tintColor={COLOR.primary} resizeMode="stretch" source={ICON.Lock} style={[appStyle.icon, { height: 26 }]} /> <Text style={{ fontSize: 35, color: COLOR.lightText, fontWeight: '200' }}>|</Text> </View> <TextInput style={styles.input} placeholderTextColor='#C1C7D0' placeholder="Password" fontSize={16} value={password} onChangeText={setPassword} secureTextEntry /> <TouchableOpacity> <FastImage tintColor={COLOR.primary} resizeMode="stretch" source={ICON.Eye} style={[appStyle.icon, { width: 26 }]} /> </TouchableOpacity> </View> {/* FORGOT PASSWORD */} <TouchableOpacity onPress={() => handleForgot()} style={{ width: windowWidth * 0.32, alignSelf: 'center', borderBottomWidth: 1, borderColor: COLOR.primary, marginTop: 30 }}> <Text style={[appStyle.text16Bold, { color: COLOR.primary }]}>Forgot Password?</Text> </TouchableOpacity> {/* BUTTON SIGN IN */} <View style={styles.next}> <AppButton icon={ICON.Next} width={70} height={70} borderRadius={35} onPress={handleLogin} /> </View> {/* SIGN UP */} <View style={styles.form3}> <Text style={styles.title3}>New member?</Text> <TouchableOpacity onPress={() => handleSignUp()}> <Text style={styles.title4}>Sign up</Text> </TouchableOpacity> </View> </SafeAreaView> ) } // 补全缺失的样式定义 const styles = { viewRow: { flexDirection: 'row', alignItems: 'center', borderBottomWidth: 1, borderColor: COLOR.lightText, paddingVertical: 12, marginHorizontal: 20, marginBottom: 20 }, rowbetween: { flexDirection: 'row', alignItems: 'center', gap: 15 }, input: { flex: 1, marginLeft: 25, color: '#000' }, next: { marginTop: windowHeight * 0.15, alignSelf: 'center' }, form3: { flexDirection: 'row', justifyContent: 'center', marginTop: windowHeight * 0.05, gap: 8 }, title3: { fontSize: 16, color: COLOR.lightText }, title4: { fontSize: 16, color: COLOR.primary, fontWeight: 'bold' } }; export default Authorization
内容的提问来源于stack exchange,提问作者Tiến Tri Vũ Trụ
相关产品推荐
相关产品推荐

