Pattern phổ biến: không điều hướng giữa Login screen và App screens trong cùng một stack.
Thay vào đó render hai stack khác nhau dựa trên auth state.
function RootNavigator() {
const { user, isLoading } = useAuth()
if (isLoading) return <SplashScreen />
return (
<NavigationContainer>
{user ? <AppStack /> : <AuthStack />}
</NavigationContainer>
)
}Lợi ích:
- Khi user null → AppStack unmount hoàn toàn → không còn stale data, không cần manually navigation.reset().
- Login flow không "lưu" lịch sử trong AppStack → user không swipe-back từ Home về Login được (security).
- Logout = chỉ cần set user = null, navigation tự switch.
Lưu ý: transition giữa AuthStack ↔ AppStack mặc định không animate (cây React unmount/remount toàn bộ). Để có animation:
- JS stack (@react-navigation/stack): screenOptions={{ animationTypeForReplace: 'pop' }} cho phép custom transition.
- Native stack (@react-navigation/native-stack): không có prop tương đương — dùng react-native-bootsplash hoặc fade overlay tự custom (Reanimated <Animated.View> ở root) để cover transition.
- Hoặc giữ wrapper component animate opacity quanh <NavigationContainer> con.
A common pattern: do not navigate between the Login screen and App screens inside the same stack.
Render two different stacks based on auth state.
function RootNavigator() {
const { user, isLoading } = useAuth()
if (isLoading) return <SplashScreen />
return (
<NavigationContainer>
{user ? <AppStack /> : <AuthStack />}
</NavigationContainer>
)
}Benefits:
- When user is null, AppStack unmounts entirely — no stale data, no need for navigation.reset().
- The login flow never enters AppStack history, so the user cannot swipe-back from Home to Login (security).
- Logout simply sets user = null and navigation switches.
Pitfall: the transition between AuthStack and AppStack does not animate by default (the React tree unmounts/remounts entirely). To add animation:
- JS stack (@react-navigation/stack): screenOptions={{ animationTypeForReplace: 'pop' }} enables a custom transition.
- Native stack (@react-navigation/native-stack): no equivalent prop — use react-native-bootsplash or a custom fade overlay (Reanimated <Animated.View> at the root) to cover the transition.
- Or wrap a component animating opacity around the inner <NavigationContainer>.