You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native登录成功后无法跳转至Home页面问题求助

React Native登录成功后无法跳转Home页面的问题排查与修复

问题根源

  1. 状态作用域不匹配:StackNavigation组件内的isLogin状态控制页面切换,但Authorization组件内的isLogin是局部状态,修改它无法影响上层导航组件的状态。
  2. 导航配置冗余:StackBegin组件中,每个<Stack.Screen>后额外手动渲染对应组件,导致组件重复实例化,干扰导航逻辑。
  3. 缺少状态持久化:未处理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ụ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:37:33