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

React Native中navigation.navigate跳转Login页面失效问题求助

React Native 导航跳转失效问题:从Logout页面无法跳转到Login页面

问题场景

点击Drawer Navigator中Logout页面的Logout按钮时,调用navigation.navigate('Authstack',{screen:'Login'})无法跳转到Authstack里的Login页面,导航完全失效。


项目相关代码

App.js

import React from 'react';
import { View } from 'react-native';
import Route from './app/components/Navigation/Route';
import FlashMessage from "react-native-flash-message";

const App = () => {
    return (
      <View style={{flex:1}}>
        <Route/>
        <FlashMessage position="top" />
      </View>
    );
};

export default App;

Route.js

import React, { useEffect, useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import 'react-native-gesture-handler';
import AsyncStorage from '@react-native-async-storage/async-storage';

import Authstack from './Authstack';
import AppStack from './Appstack';

function Route() {
  const [token, setToken] = useState('');

  useEffect(()=>{
    loadApp()
  },[]);

  loadApp = async()=>{
    const loggedToken =  await AsyncStorage.getItem('userToken');
    setToken(loggedToken);
  }

    return (
      <NavigationContainer>
        { (token ? <AppStack/> : <Authstack/>)}
      </NavigationContainer>
    );
  }

export default Route;

Authstack.js

import React from 'react';
import 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/Ionicons';
import {createNativeStackNavigator} from '@react-navigation/native-stack';

import {Login, Profile} from '..';
import AppStack from  './Appstack';

export default function Authstack(){
    const Stack = createNativeStackNavigator();
    return(
        <Stack.Navigator initialRouteName='Login'>
            <Stack.Screen name="Login" component={Login} options={{ title: 'Login' ,headerStyle: { backgroundColor: '#b61b1b', },
                headerTintColor: 'white',headerTitleStyle: {fontWeight: 'bold',},}} />
            <Stack.Screen name="AppStack" component={AppStack} options={{ header: false }}/>
        </Stack.Navigator>
    );
}

Appstack.js

import React from 'react';
import Icon from 'react-native-vector-icons/Ionicons';
import { createDrawerNavigator } from '@react-navigation/drawer';

import SidebarMenu from  './SidebarMenu';
import {Profile, Salary, Attendance, Insurance, Leave, Loan,Logout,Sidebar} from '..';

export default function AppStack(){
const Drawer = createDrawerNavigator();

  const loadIcon =(name)=>{
    return <Icon name={name} size={20} color='#b61b1b'/>
  }

    return(
          <Drawer.Navigator screenOptions={{headerStyle: {
            backgroundColor: '#b61b1b', },headerTintColor: '#fff',headerTitleStyle: {fontWeight: 'bold' },}}
            drawerContentOptions={{activeTintColor: '#e91e63',itemStyle: { marginVertical: 5 }, }} 
            drawerContent={(props)=> <SidebarMenu {...props} /> }>
            <Drawer.Screen name="Profile" component={Profile} options={{drawerIcon: () => (loadIcon('person-circle-outline')),}} />
            <Drawer.Screen name="Attendance" component={Attendance} options={{drawerIcon: () => (loadIcon('alarm-outline')),}} />
            <Drawer.Screen name="Salary" component={Salary} options={{drawerIcon: () => (loadIcon('cash-outline')),}} />
            <Drawer.Screen name="Leave" component={Leave} options={{drawerIcon: () => (loadIcon('calendar-outline')),}} />
            <Drawer.Screen name="Loan" component={Loan} options={{drawerIcon: () => (loadIcon('business-outline')),}} />
            <Drawer.Screen name="Logout" component={Logout} options={{drawerIcon: () => (loadIcon('exit-outline')),}} />
          </Drawer.Navigator>
    );
}

Logout.js

import { View, Text,Button } from 'react-native'
import React from 'react'

const Logout = ({navigation}) => {
  return (
    <View>
      <Text>Logout</Text>
      <Button title="Logout" onPress={()=>navigation.navigate('Authstack',{screen:'Login'})} />
    </View>
  )
}

export default Logout

问题原因

你的导航结构是条件渲染切换整个栈(Route.js中根据token显示AppStack或Authstack),而非将两个栈嵌套在同一导航容器下。AppStack内部的导航无法直接访问Authstack——因为二者是同级、互斥的渲染项,不属于同一导航树,navigation.navigate只能访问当前导航树内的路由。


修复方案

方案1:状态驱动路由切换(推荐,改动最小)

利用现有架构的状态逻辑,注销时清理token并更新状态,自动触发Route.js的条件渲染切换到Authstack:

修改Logout.js:

import { View, Text, Button, Alert } from 'react-native'
import React from 'react'
import AsyncStorage from '@react-native-async-storage/async-storage';

const Logout = () => {
  const handleLogout = async () => {
    try {
      // 清除存储的token
      await AsyncStorage.removeItem('userToken');
      // 无需手动导航,Route的token状态更新后会自动切换到Authstack
    } catch (error) {
      Alert.alert('错误', '注销失败,请重试');
    }
  }

  return (
    <View>
      <Text>Logout</Text>
      <Button title="Logout" onPress={handleLogout} />
    </View>
  )
}

export default Logout

优化Route.js的加载逻辑,避免初始闪屏:

import React, { useEffect, useState } from 'react';
import { NavigationContainer, ActivityIndicator, View } from '@react-navigation/native';
import 'react-native-gesture-handler';
import AsyncStorage from '@react-native-async-storage/async-storage';

import Authstack from './Authstack';
import AppStack from './Appstack';

function Route() {
  const [token, setToken] = useState(null); // 初始null表示加载中
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    loadApp();
  }, []);

  const loadApp = async () => {
    try {
      const loggedToken = await AsyncStorage.getItem('userToken');
      setToken(loggedToken);
    } catch (error) {
      console.error('加载token失败:', error);
      setToken(null);
    } finally {
      setIsLoading(false);
    }
  }

  // 加载中UI
  if (isLoading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <ActivityIndicator size="large" color="#b61b1b" />
      </View>
    );
  }

  return (
    <NavigationContainer>
      {token ? <AppStack /> : <Authstack />}
    </NavigationContainer>
  );
}

export default Route;

方案2:重构为嵌套根栈(支持跨栈导航)

若需保留navigation跳转逻辑,可将两个栈嵌套在根栈中,使它们处于同一导航树:

修改Route.js为根栈结构:

import React, { useEffect, useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import 'react-native-gesture-handler';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

import Authstack from './Authstack';
import AppStack from './Appstack';

const Stack = createNativeStackNavigator();

function Route() {
  const [token, setToken] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    loadApp();
  }, []);

  const loadApp = async () => {
    const loggedToken = await AsyncStorage.getItem('userToken');
    setToken(loggedToken);
    setIsLoading(false);
  }

  if (isLoading) return null;

  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{ headerShown: false }}>
        {token ? (
          <Stack.Screen name="AppStack" component={AppStack} />
        ) : (
          <Stack.Screen name="Authstack" component={Authstack} />
        )}
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default Route;

修改Logout.js的跳转逻辑(用reset避免遗留历史栈):

import { View, Text, Button, Alert } from 'react-native'
import React from 'react'
import AsyncStorage from '@react-native-async-storage/async-storage';

const Logout = ({ navigation }) => {
  const handleLogout = async () => {
    try {
      await AsyncStorage.removeItem('userToken');
      navigation.reset({
        index: 0,
        routes: [{ name: 'Authstack', params: { screen: 'Login' } }],
      });
    } catch (error) {
      Alert.alert('错误', '注销失败');
    }
  }

  return (
    <View>
      <Text>Logout</Text>
      <Button title="Logout" onPress={handleLogout} />
    </View>
  )
}

export default Logout

关键注意点

  • 不要在条件渲染的同级栈之间用navigation.navigate,二者不属于同一导航树
  • 注销必须清理AsyncStorage中的token,否则重启App会自动回到AppStack
  • 状态驱动的路由切换更符合现有架构,代码改动最小且稳定性更高

内容的提问来源于stack exchange,提问作者Buddhika Athukorala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:54:55