skip to Main Content

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 to LogInScreen.

  • User in anywhere else causes some error -> SomeErrorScreen shows -> User press button to go back to first screen in AppTabsNavigator (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


  1. 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.

    {!loggedIn ? (
          // Login
          <Stack.Group>
            <Stack.Screen name="RootScreen" component={LogInScreen} /> 
          </Stack.Group>
        ) : (
          // App Screens
          <Stack.Group>
            // This Tab navigator may have more stacks inside
            <Stack.Screen name="RootScreen" component={AppTabsNavigator} />
            <Stack.Screen name="SomeErrorOutsideTabs" component={SomeErrorOutsideTabs} /> 
          </Stack.Group>
        )}
    
    Login or Signup to reply.
  2. You can reset your navigator

    navigation.reset({
                index: 0,
                routes: [
                  {
                    name: 'SomeStackScreen',
                    params: { someParam: 'Param1' },
                  },
                ],
              })
    

    As seen in the docs here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search