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

expo-router基于会话状态路由失效,登出时router.push失败

Expo Router 条件路由与登出跳转问题解决

一、条件路由不生效问题

你当前在根布局中通过条件渲染Stack.Screen的方式控制路由,这不符合Expo Router的工作逻辑——Stack.Screen是用来注册路由映射的,而非动态控制页面跳转。即便你条件渲染了某个Screen,Expo Router仍会根据默认路由规则(比如优先加载(tabs)下的页面)展示内容,这就是为什么始终跳转到index.tsx的原因。

修复方案:使用重定向逻辑

在根布局中,根据会话状态直接执行重定向操作,推荐两种方式:

方式1:使用Redirect组件(Expo Router v2+支持)

修改app/_layout.tsx:

import React from 'react';
import { View, Text } from 'react-native';
import { Stack, Redirect } from 'expo-router';
import { useAuth } from '../context/AuthContext';

function AppContent() {
  const { session, isLoading } = useAuth();

  if (isLoading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Loading...</Text>
      </View>
    );
  }

  // 无会话时重定向到auth,否则正常渲染栈
  if (!session || !session.user) {
    return <Redirect href="/auth" />;
  }

  return (
    <Stack screenOptions={{ headerShown: false }}>
      {/* 注册所有需要的路由,而非条件渲染 */}
      <Stack.Screen name="auth" options={{ headerShown: false }} />
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
    </Stack>
  );
}

export default function App() {
  return (
    <AuthProvider>
      <AppContent />
    </AuthProvider>
  );
}

方式2:使用useRouter结合useEffect

如果你的Expo Router版本较低,可通过监听会话变化实现重定向:

import React, { useEffect } from 'react';
import { View, Text } from 'react-native';
import { Stack, useRouter } from 'expo-router';
import { useAuth } from '../context/AuthContext';

function AppContent() {
  const { session, isLoading } = useAuth();
  const router = useRouter();

  useEffect(() => {
    if (!isLoading) {
      if (!session || !session.user) {
        router.replace('/auth'); // 使用replace避免回退栈问题
      } else {
        router.replace('/(tabs)');
      }
    }
  }, [session, isLoading]);

  if (isLoading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Loading...</Text>
      </View>
    );
  }

  return (
    <Stack screenOptions={{ headerShown: false }}>
      <Stack.Screen name="auth" options={{ headerShown: false }} />
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
    </Stack>
  );
}

export default function App() {
  return (
    <AuthProvider>
      <AppContent />
    </AuthProvider>
  );
}

二、登出跳转路由不存在问题

你的登出代码中router.push的路径完全错误:Expo Router的路由路径基于app目录结构,不需要带.tsx后缀,也不需要完整的文件路径。

修复方案:使用正确的路由路径

修改登出按钮代码:

// 方式1:绝对路径(推荐)
<TouchableOpacity onPress={async () => {
    try {
        const { error } = await supabase.auth.signOut();
        if (error) {
            console.error('Error signing out:', error.message);
        } else {
            console.log('Successfully logged out');
            router.replace('/auth'); // 用replace避免回退到已登出的页面
        }
    } catch (err) {
        console.error('Unexpected error during sign out:', err);
    }
}}>
    <Text style={[styles.drawerItem, styles.logout]}>Logout</Text>
</TouchableOpacity>

// 方式2:相对路径(如果当前页面在(tabs)下)
<Button
    title="Sign Out"
    onPress={async () => {
        await supabase.auth.signOut();
        router.replace('../auth'); // 相对路径向上一级到app目录,再指向auth
    }}
    color="#34d399"
/>

注意点:

  • 优先使用router.replace而非push,避免用户点击返回键回到已登出的会话页面。
  • 确保AuthContext中的session状态在登出后能及时更新,否则重定向逻辑不会触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:23:16