I’m working on a React Native project using expo-router, and I’m having an issue with conditional routing based on the session state. I want to navigate to a login screen (auth.tsx) if there’s no active session, or to a tab-based screen ((tabs)/index.tsx) if the user is logged in.
Problem:
- The app always seems to navigate to the index.tsx file, even though I’m using expo-router with conditional routing based on session state.
- When I check the session state, it’s correctly logged, but the route isn’t behaving as expected.
- Additionally, when I try to sign out using router.push(‘app/auth.tsx’), the navigation doesn’t work, and it returns an error that the route could not be found.
Please help me out.
// app/_layout.tsx (this is the root layout)
import React, { useEffect } from 'react';
import { View, Text } from 'react-native';
import { Stack } 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>
);
}
return (
<Stack screenOptions={{ headerShown: false }}>
{!session || !session.user ? ( // this does not work
// Navigate to auth if session is null, undefined, or invalid
<Stack.Screen name="auth" options={{ headerShown: false }} />
) : (
// Navigate to (tabs) if session and user are valid
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
)}
</Stack>
);
}
export default function App() {
return (
<AuthProvider>
<AppContent />
</AuthProvider>
);
}
I’ve made sure that the file structure matches expo-router conventions:
/app
├── auth.tsx // Login screen
├── _layout.tsx // Root layout
└── (tabs)
└── index.tsx // Tab-based screen
└── _layout.tsx // Tab-based layout
Sign Out Buttons:
<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');
// Sign out the user
await router.push('../../app/auth.tsx');
}
} catch (err) {
console.error('Unexpected error during sign out:', err);
}
}}>
<Text style={[styles.drawerItem, styles.logout]}>Logout</Text>
</TouchableOpacity>
<Button
title="Sign Out"
onPress={async () => {
await supabase.auth.signOut(); // Sign out the user
router.push('/app/Auth.tsx'); // Navigate to the Auth page
}}
color="#34d399"
/>
2
Answers
For your specific case, you can try using the
redirect
prop (although there could be a better way to achieve this).In the root layout component you have pasted, try the following (notice the
redirect
prop for the second screen):This way, whenever the value of
session
gets altered and the redirect condition is satisfied (which you have confirmed it does), you will be redirected to theauth
route.