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
相关产品推荐
相关产品推荐

