Nested React Native navigators
Tags: reactnative
Published: 2020-05-04 14:19:18

---
title: Nested React Native navigators
published: true
date: 2020-04-07 17:30:51 UTC
tags: reactnative
canonical_url: https://blog.logrocket.com/nested-react-native-navigators/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/v9ku92ch39j5r7otmq50.png
---
**Written by [Kitavi Joseph](https://blog.logrocket.com/author/kitavijoseph/)**✏️

Mobile applications normally have multiple screens that the user can interact with to access different functionalities on the app. The biggest challenge when developing a mobile app is figuring out how to bundle the screens together and providing the easiest way for the user to navigate and interact with these screens.

Most mobile applications will have a combination of navigators nested together to provide the best possible experience for navigating through the screens which improves the user experience on the app itself.

## Prerequisites

To follow along with this article, you should have:

- A basic understanding of React Native
- React Native [set up](https://reactnative.dev/docs/getting-started) on your development machine

## Why React Navigation?

When developing using React Native there are several options for navigation libraries you can use to implement the desired navigation you want on the app. Some of them include [React Navigation](https://reactnavigation.org), [react-native-router-flux](https://www.npmjs.com/package/react-native-router-flux), and [react-native-navigation](https://wix.github.io/react-native-navigation/#/).

In this blog, we will use [React Navigation](https://reactnavigation.org) to implement the different navigators. React Navigation is easy to use, with a big community to help with issues along the base, and very detailed [documentation](https://reactnavigation.org/docs/en/getting-started.html). On top of all this, it is the recommended navigation library in the [React Native docs](https://facebook.github.io/react-native/docs/navigation).

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## Setup

To begin, we will need to set up the app where we will implement the navigation in. If you don’t have React Native set up please visit the [React Native getting started docs](https://reactnative.dev/docs/getting-started) and once you have that set up pick up from here.

Set up a React Native app using `react-native init`:

```jsx
  npx react-native init NestedNavigation
```

This should set up a React Native project under the folder `NestedNavigation` . Make sure that runs properly on your simulator or device for either platform (iOS or Android). You should have the React Native welcome screen displaying, like this:

![welcome to react native screen](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/welcometoreactscreen.png?resize=730%2C1337&ssl=1)

Let’s move around a few files to get the app ready for some coding. Let’s create a `src` folder where most of our code will reside. Then move the `App.js` file into the created `src` folder, updating the file structure to look something like this:

![react native app structure](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/reactnativeappstructure.png?resize=518%2C504&ssl=1)

Update the import path for `App.js` on `index.js` to include the updated folder name and reload your app:

```jsx
// index.js
import { AppRegistry } from 'react-native'
import App from './src/App'
import { name as appName } from './app.json'

AppRegistry.registerComponent(appName, () => App)
```

Now, when your app reloads you should be able to see the welcome screen that is shown previously in this section.

## Adding navigation library

For the setup, let’s install React Navigation which we will use for the navigation. Please visit the React Navigation v4 [getting started page](https://reactnavigation.org/docs/4.x/getting-started) for the full details on setup. Here is a short walkthrough of the setup.

Install React Navigation v4 and it’s dependencies as shown below:

```jsx
yarn add react-navigation@4.2.2

yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
```

For iOS be sure to install the pods:

```jsx
cd ios; pod install; cd ..
```

For Android, we will need to make a few changes on `MainActivity.java`. Add the following lines:

```jsx
...
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

public class MainActivity extends ReactActivity {
  ...
  @Override
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
      @Override
      protected ReactRootView createRootView() {
        return new RNGestureHandlerEnabledRootView(MainActivity.this);
      }
    };
  }
}
```

After the platform setup, we’ll finish up with importing the gesture handler to `index.js`:

```jsx
  // index.js
    import 'react-native-gesture-handler';
```

Now, run the app to confirm that setup was successful. You should see the “Welcome to React” screen again.

Before we get on adding the navigators, let’s have an overview of the navigation we will be seeking to implement. We will begin with a [switch navigator](https://reactnavigation.org/docs/4.x/switch-navigator/) for switching between application screens and authentication screens. Then we’ll have a [drawer navigator](https://reactnavigation.org/docs/4.x/drawer-based-navigation) which will then contain the [tab navigator](https://reactnavigation.org/docs/4.x/tab-based-navigation) and [stack navigator](https://reactnavigation.org/docs/4.x/stack-navigator).

## Adding a switch navigator

We are going to begin by setting up the switch navigator. This navigator, as the name suggests, switches between different screens( e.g. switching between the loading screen to either login screen or home screen). This navigator doesn’t handle back action and displays only one screen at a time which makes it ideal for authentication flows. We will add three screens for our switch navigator:

- AuthLoading screen for checking login status
- Login screen to handle authentication
- Home screen for default landing screen

Create a `components` folder in `src` directory and create the screens mentioned above (`AuthLoading.js`, `Login.js`, and `Home.js`). Let’s add some simple code for the screens we’ve created. Copy the code below to each file and be sure to update the class names, display text, and exports to match each file:

```jsx
// AuthLoading.js / Login.js / Home.js
import React from 'react'
import { StyleSheet, View, Text } from 'react-native'

class AuthLoading extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>AuthLoading Screen</Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
})

export default AuthLoading
```

Finally, we can get our switch navigator up and running.

Let’s jump on to `App.js` delete everything on there and replace it with this, then I’ll explain what magic we are trying to pull here:

```jsx
// App.js
import React from 'react'
import { SafeAreaView, StyleSheet } from 'react-native'
import { createAppContainer, createStackNavigator } from 'react-navigation'

import Login from './components/Login'
import AuthLoading from './components/AuthLoading'
import Home from './components/Home'

const switchNavigator = createSwitchNavigator(
  {
    AuthLoading,
    Login,
    Home,
  },
  {
    initialRouteName: 'AuthLoading',
  },
)

const AppNavigator = createAppContainer(switchNavigator)

class App extends React.Component {
  render() {
    return (
      <SafeAreaView style={styles.container}>
        <AppNavigator />
      </SafeAreaView>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
})

export default App
```

We start with the usual, imports from `react`, `react-native`, and `react-navigation`. As seen above we import `createSwitchNavigator` used to set up the switch navigator and `createAppContainer` which is used as the root navigator in React Navigation.

Then we finalize the imports by adding the screens we want to use in the navigator (as seen in the set up for switch navigator). In the navigator configurations for the switch navigator, we set `AuthLoading` as the initial route, since it’s the first screen we want to load before switching to either the login or home screen depending on authentication status.

When we reload the app right now, it should display the `AuthLoading` screen as seen below without any navigation to either the login or home screens:

![Auth loading screen in react native app](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/authloading.png?resize=912%2C1660&ssl=1)

With this working, let’s give the  `AuthLoading` screen the power to switch between the other two screens depending on the authentication status. Since this isn’t a blog about authentication in React Native, we are going to hack our way around this:

```jsx
// AuthLoading.js
...
import { ActivityIndicator, StyleSheet, View, Text } from 'react-native'


class AuthLoading extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      loggedIn: false,
    }
  }

  checkLoggedInStatus = () => {
    if (this.state.loggedIn) {
      return this.props.navigation.navigate('Home')
    }

    return this.props.navigation.navigate('Login')
  }

  componentDidMount() {
    this.checkLoggedInStatus()
  }

...

        <Text>AuthLoading Screen</Text>
        <ActivityIndicator />
...
```

We are going to add a state to store our virtual logged in status, which can either be true or false depending on whether or not the user is logged in. Then we will create a function `checkLoggedInStatus` that checks the user status and either navigates us to the home screen or login screen as needed. Then in our `componentDidMount` we will call a function so that it’s run every time `AuthLoading` is mounted. As a bonus, we also added an `ActivityIndicator` to show loading status before switching the app.

Feel free to play around with this by toggling the logged-in status and checking which screen is rendered.

Finally, let’s add a login button in `Login` screen to mimic a login and navigate the user to the home screen:

```jsx
// Login.js
...
import { StyleSheet, View, Text, TouchableOpacity } from 'react-native'

class Login extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Login Screen.</Text>
        <TouchableOpacity
          style={styles.loginButton}
          onPress={() => this.props.navigation.navigate('Home')}>
          <Text>Login</Text>
        </TouchableOpacity>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  loginButton: {
    height: 30,
    width: '40%',
    margin: 5,
    borderWidth: 1,
    borderRadius: 5,
    alignItems: 'center',
    justifyContent: 'center',
  },

...
```

We create a login screen that will be displayed when the user is not logged in and added a login button that mimics the user login and navigates the user to the home screen after successful login. With all this done, we should have a smooth switch navigator working and producing some navigation as seen below, checking the logged-in status and navigating to the login screen then home screen after logging in:

![auth to home](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/authtohome.gif?resize=730%2C1464&ssl=1)

## Adding a drawer navigator

[Drawer navigators](https://reactnavigation.org/docs/4.x/drawer-navigator) provide users with very easy and intuitive navigation. Pulling the side menu either from the left or right to view more options and navigate between screens. When using the drawer navigator it has to be the base navigator for the rest of the app, hence why we are covering it first.

Let’s get to it. Let’s install the necessary requirements for the navigator:

```jsx
yarn add react-navigation-drawer
```

Now let’s jump onto `App.js` and spin up the drawer navigator, this will require a few updates on this file to import the drawer navigator and set it up:

```jsx
// App.js
...
import { createDrawerNavigator } from 'react-navigation-drawer' // import drawer nav

const DrawerNavigator = createDrawerNavigator(
  {
    Home, // move Home screen to drawer
  },
)

const switchNavigator = createSwitchNavigator(
  {
    AuthLoading,
    Login,
    DrawerNavigator, // change this to DrawerNavigator
  },
  {
    initialRouteName: 'AuthLoading',
  },
)

...
```

We import the `createDrawerNavigator` function and set up our `DrawerNavigator` with the home screen in it. We will add more screens to that later, of course, but for the initial setup let’s just go with the one for now and get the navigator up.

With the home screen moved into the drawer navigator, we replace it on the switch navigator with the newly created `DrawerNavigator` so that after the authentication flow the app navigates to the drawer navigator. Remember to update `checkLoggedInStatus` function on `AuthLoading.js` to navigate to the updated route name `DrawerNavigator` :

```jsx
// AuthLoading.js
...

  checkLoggedInStatus = () => {
    if (this.state.loggedIn) {
      return this.props.navigation.navigate('DrawerNavigator')
    }
    return this.props.navigation.navigate('Login')
  }
```

With this setup, reload the app and it should navigate to the drawer navigator and open the home screen with the side menu ready to go. Swiping from the left should open it up and display the side menu with only the home screen option though.

![navigate to drawer navigator](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/navigatetodrawernavigator.gif?resize=600%2C1243&ssl=1)

So let’s add another screen to be able to demonstrate navigation between different screens. In the components folder, create `Settings.js` file and copy the contents of `Login.js` into it, update the class names and make the followings updates to it:

```jsx
// Settings.js
...

class Settings extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Settings Screen</Text>

        <TouchableOpacity
          style={styles.loginButton}
          onPress={() => this.props.navigation.openDrawer()}>
          <Text>Open Drawer</Text>
        </TouchableOpacity>
      </View>
    )
  }
}

...
export default Settings
```

As you noticed we added`openDrawer()` function that will open the drawer without the need to swipe from the left. Now to have view settings screen let’s add it to the `DrawerNavigator` in `App.js`:

```jsx
// App.js
...
import Settings from './components/Settings'

const DrawerNavigator = createDrawerNavigator(
  {
    Home,
    Settings,
  },
  {
    initialRouteName: 'Home'
  }
)

...
```

We also set the `initialRouteName` in the drawer navigator configs so that the drawer navigator displays the home screen first. With this done our drawer navigation is good to go. Let’s reload our app and see where we are at.

You can further customize the side menu to your liking, but we won’t cover that in this post.

![navigator opens to home screen](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/navigatorhomesceen.gif?resize=730%2C1512&ssl=1)

## Add a tab navigator in drawer

Tab navigator uses a tab bar located on either the top or bottom of the screen that lets you switch between different routes. Screens on tab navigators don’t get mounted until they are focused. This navigator provides nice navigation for switching between content on the screen (for example, in WhatsApp when you switch between chats, status, and calls or on Twitter when you switch between home, search, notifications, and messages).

In React Navigation, there are a few options to set up your tab navigator, you can use either `createBottomTabNavigator` (default), `createMaterialBottomTabNavigator`, or `createMaterialTopTabNavigator`. As the name suggests the last two are material-design themed tabs located at the bottom or top respectively. In this walkthrough, we will use the default option (`createBottomTabNavigator`).

We will, of course, start by installing the required dependencies:

```jsx
yarn add react-navigation-tabs
```

For simplicity, we will create one file `WeekDays.js` in our `components` folder which will contain three-tab components for `Monday`, `Tuesday`, and `Wednesday` which we will use in our `App.js` to set up the tab navigator:

```jsx
// WeekDays.js
import React from 'react'
import { StyleSheet, View, Text } from 'react-native'

export class Monday extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Monday Blues</Text>
      </View>
    )
  }
}
export class Tuesday extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Tuesday Thoughts</Text>
      </View>
    )
  }
}
export class Wednesday extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Wednesday Wisdom</Text>
      </View>
    )
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
})
```

With the tab screens ready to go, it’s time to create the tab navigator, let’s jump into the App.js screen and get that going:

```jsx
// App.js
...
import { createBottomTabNavigator } from 'react-navigation-tabs'
import { Monday, Tuesday, Wednesday } from './components/TabScreens'

const WeekDays = createBottomTabNavigator(
  {
    Monday,
    Tuesday,
    Wednesday,
  }
)

const DrawerNavigator = createDrawerNavigator(
  {
    Home,
    Settings,
    WeekDays, // add bottom navigator here
  },
  ...
)

...
```

With this in place, we should have `WeekDays` option on the side menu, which will then display the different tab options as seen below:

![side menu with week days listed](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/weekdaysoption.gif?resize=730%2C1512&ssl=1)

## Adding a stack navigator

Finally the last navigator we will talk about is the stack navigator. This navigator moves between different screens by placing the new screens on top of a stack. Stack navigator is pretty simple — a new screen is placed on top of the stack and to view previous screens you just navigate back.

```jsx
yarn add react-navigation-stack @react-native-community/masked-view
```

For this, we are going to add profile settings to our app, which ideally should be on the same stack with settings. Let’s create `ProfileSettings.js` and then set up the settings stack navigation:

```jsx
// ProfileSettings.js
import React from 'react'
import { StyleSheet, View, Text } from 'react-native'

class ProfileSettings extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Profile Settings Screen</Text>
      </View>
    )
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
})
export default ProfileSettings
```

With this ready now we can make final changes to our `App.js` to add our stack navigator. After necessary imports, we initialize the stack navigator and move settings screen into it as well as the new `ProfileSettings`. On the drawer navigator, we also update it to point to the `AllSettings` stack navigator that contains our settings screen:

```jsx
// App.js

...
import { createStackNavigator } from 'react-navigation-stack'
import ProfileSettings from './components/ProfileSettings'

const AllSettings = createStackNavigator(
  {
    Settings,
    ProfileSettings,
  }
)
const DrawerNavigator = createDrawerNavigator(
  {
    Home,
    AllSettings, // update this
    WeekDays,
  },
  {
    initialRouteName: 'Home',
  },
)
```

With this done, the app should run successfully, you should also be able to navigate to `AllSettings` from the drawer navigator which will display the settings screen. Also, notice there isn’t a way to navigate between the settings and profile settings screen. Let’s fix that from the settings screen by adding a button to navigate to profile settings from setting:

```jsx
// Settings.js

...
        <TouchableOpacity
          style={styles.loginButton}
          onPress={() => this.props.navigation.openDrawer()}>
          <Text>Open Drawer</Text>
        </TouchableOpacity>

        <TouchableOpacity // add this
          style={styles.loginButton}
          onPress={() => this.props.navigation.navigate('ProfileSettings')}>
          <Text>Profile Settings</Text>
        </TouchableOpacity>

...
```

With this we should be able to navigate to profile settings using the button added above and navigate back using the native back button provided by the stack navigator, like this:  
 ![navigate back button in use](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/navigateback.gif?resize=364%2C754&ssl=1)

## Conclusion

Voila, we are done with nested navigation!

We started out with a switch navigator to handle authentication states, then we created a drawer navigator which should be the base navigator when used and on top of that added the tab and stack navigators. The last two can be nested in whichever order you prefer.

The code for this can be found [on Github](https://github.com/jmkitavi/NestedNavigation).

![all navigators being shown in the react native app](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/finalproduct-1.gif?resize=730%2C1500&ssl=1)

* * * 
## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *

The post [Nested React Native navigators](https://blog.logrocket.com/nested-react-native-navigators/) appeared first on [LogRocket Blog](https://blog.logrocket.com).