Nicoară Talpeș

web and mobile developer

Navigate from nested navigator to parent in React Native

This blog post will handle a navigation difficulty in iOS and Android mobile apps coded using React Native.

Problem presentation:

The use case is simple:

The environment is an app coded with React Native that uses as navigation the React Navigation library. At launch, before going into the main part of the application, we first direct the user to log-in. Once logged in, from within the app, we want to have a screen where the user can log out if neccesary, and then be redirected back to log-in.

The structure of the app is the following:

app.js contains the top-level navigator. Initially the Splash screen looks into local storage to see if there is a user logged in; if not, it goes to Auth screen where the log in is. On log in success it redirects to Main screen.


        app.js:
        const AppNavigator = StackNavigator({
                splash: { screen: SplashScreen },
                auth: { screen: AuthScreen },
                main: { screen: MainScreen }
            }
        );
        
        MainScreen.js:
        const MainNavigator = TabNavigator({
            map: { screen: MapScreen },
            logout: { screen: LogoutScreen }
        });
        

We have a parent Stack Navigator with a nested Tab Navigator, and we want to navigate from inside the Logout screen to the Auth screen.

The problem we encounter is that calling in Logout.js:


this.props.navigation.navigate('auth');
            

does not do anything, since the child TabNavigator just has knowledge of the routes inside of itself.

I found this difficulty talked about on Stack Overflow and the official community pages here and here .

Solution

We know the Stack and Tab navigators have an object called NavigationActions which exposes multiple actions. One of those actions, the Navigate action, will link the current screen to another screen in the app. As we have tried already, we tant to use this action to go from Logout to Auth.

We reformulate the problem: How to get access inside a component (the TabNavigator) to an object of a parent component (the Stack Navigator)?

With the primary means of making components reusable in React Native: passing it as a prop.

MainScreen will pass the navigation object of the Stack Navigator as a prop to all the screens it is a TabNavigator for, including Logout:

        MainScreen.js:
        return (
                < MainNavigator screenProps={this.props.navigation} />
        );

        Logout.js: 
        this.props.screenProps.navigate('auth');
        

One last thing:

On Android, the user can press the back button on the actual device. We prevent this in Logout.js by navigating and resetting the stack:


        Logout.js:
        const resetAction = NavigationActions.reset({
            index: 0,
            actions: [NavigationActions.navigate({ routeName: 'auth' })],
        });
        this.props.screenProps.dispatch(resetAction); 

        

The React Navigation library is still the React Native community's recommendation for navigation. This solution proves its flexibility in confusing situations.


Posted on March 7, 2018