I’m using react navigation in a react native project and i am unable to find how to go back to navigation root (first screen in app) from an arbitrary screen. Navigation is like this:
<NavigationContainer>
<Stack.Navigator>
{!loggedIn ? (
// Login
<Stack.Group>
<Stack.Screen name="LogInScreen" component={LogInScreen} />
</Stack.Group>
) : (
// App Screens
<Stack.Group>
// This Tab navigator may have more stacks inside
<Stack.Screen name="AppTabsNavigator" component={AppTabsNavigator} />
<Stack.Screen name="SomeErrorOutsideTabs" component={SomeErrorOutsideTabs} />
</Stack.Group>
)}
// Error Modals
<Stack.Group>
<Stack.Screen name="SomeErrorScreen" component={SomeErrorScreen} />
</Stack.Group>
<Stack.Navigator>
</NavigationContrainer>
Use cases are:
-
User in
LogInScreen
causes some error ->SomeErrorScreen
shows -> User press button to go back toLogInScreen
. -
User in anywhere else causes some error ->
SomeErrorScreen
shows -> User press button to go back to first screen inAppTabsNavigator
(sometimes does not work depending on inner stacks).
The summary is, no matter where you are, when you press button in SomeErrorScreen
you must go back to "first app screen", which is LogInScreen
if not logged in or first tab of AppTabsNavigator
if logged in.
I have tried using popToTop()
but it does not work when there are inners Stacks like SomeResourceStack
inside AppTabsNavigator
to contain index and show of resource, for example:
User in AppTabsNavigator > SomeResourceStack > index
access to AppTabsNavigator > SomeResourceStack > show
, cause SomeErrorScreen
to appear and when going back, he goes back to AppTabsNavigator > SomeResourceStack > show
instead of AppTabsNavigator
first tab.
Answer:
The right answer is to use reset
like Anthony Marino said and combine it with Ararat Ispiroglu suggestion. I controlled Android’s back button behavior as well:
...
import { BackHandler } from 'react-native'
import { useFocusEffect } from '@react-navigation/native'
import { useSelector } from 'react-redux'
...
const SomeErrorScreen = ({ navigation }) => {
...
const loggedIn = useSelector(state => state.auth.loggedIn)
const onGoingBackButtonPress = React.useCallback(() => {
navigation.reset({
index: 0,
routes: [{ name: !loggedIn ? 'LogInScreen' : 'AppTabsNavigator' }]
})
}, [navigation, loggedIn])
const androidBackButtonCallback = React.useCallback(() => {
const onBackPress = () => {
onGoingBackButtonPress()
return true
}
BackHandler.addEventListener('hardwareBackPress', onBackPress)
return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress)
}, [onGoingBackButtonPress])
useFocusEffect(androidBackButtonCallback)
...
return <View>
<Button onPress={onGoingBackButtonPress } />
</View>
}
export default SomeErrorScreen
2
Answers
You have two options to do that with your current navigation setup;
a) When you need to go back to root you can check if it’s logged in or not
simply
navigation.navigate(loggedIn ? "AppTabsNavigator" : "LogInScreen")
b) You can set the same name for the top level screen in the navigation for both logged and non-logged in screens. And navigation will pickup whichever screen is mouthed.
You can reset your navigator
As seen in the docs here