Post navigation

Apps

How to set up Expo app navigation using React Navigation

Further to my previous post about how to build a react native app using Expo, this post takes it a step further and shows you how to set up all 3 types of Expo navigation in your app – Stack Navigation, Tab Navigation, and Drawer Navigation. By the time you’ve worked through both posts you should have a simple Expo app running on your device with the ability to navigate in different ways between pages. I’ll also cover some basic styling, so by the end you will have a great app framework to build on.

Which Expo navigation package?

There are a few different navigation packages available for Expo (React Navigation, React Router…) but for this article we’ll be using React Navigation, which is recommended to be used with Expo. I’ve never had any issues with it and I also know it works well with Redux. I won’t go into that now but it will become important as you build more complex apps, so it’s worth mentioning. Full details are here – https://reactnavigation.org/docs/getting-started/.

I’m presuming you’ve read my first Expo post, and completed all the steps. In that case you’ll already have a basic Expo app installed and running. That’s where this post takes over….

First of all you need to install the React Navigation package itself, so on the command line type this:

npm install @react-navigation/native

And then this, to install Expo dependencies:

expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view

Now you’re ready to start coding your pages and then navigating between them, and for this you need to install the Stack Navigator.

Expo stack navigator for basic navigation

The stack navigator is the simplest of the three, and let’s you simply move from one page to another using a link or button that you have put on your page. You’ll then define a ‘stack of pages’ and navigate through them. To install the Stack Navigator, type this :

npm install @react-navigation/stack

Once installed, we can start coding a simple 2 screen Expo app that let’s you navigate to and from each screen. This is the most basic navigation set up. First of all you need to reference all required packages in your app.js file :

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { StyleSheet, Text, Button, View } from 'react-native';

… and then create a Stack Navigator.

const Stack = createStackNavigator();

Next we build the method for our pages, one for the Home page, and one for the Details page :

function Home({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>Home Screen</Text>
      <Button
        title="Show me the Details screen"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

function Details({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Details page</Text>
      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

NOTE – I’ve included a bit of styling, which just makes sure the page content is centred nicely. Now we’ll build up the main method in app.js, which defines the overall StackNavigator and specifies which page to show first, in the initialRouteName property.

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={Home} />
        <Stack.Screen name="Details" component={Details} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Now run that to test your changes – type expo start on the command line if it is not already running. Or simply save your file to refresh it if it already is. You’ll see the Home page load with a button on it. That button takes you to the Details screen, and on the Details screen is another button which takes you back to the Home screen. And that is all you need for some simple Expo navigation!

You’ll probably find that you also want to have another type of navigation in your app, either some Tab navigation, or Drawer navigation. Read on for how to combine them.

Combining stack navigation with tab navigation in Expo

Before you can add tab navigation to your Expo app, you need to decide whether you want to install top tabs or bottom tabs, and whether you want to :

  • nest a Stack Navigator in a Tab Navigator – or
  • nest a Tab Navigator in a Stack Navigator

I’m going to add some bottom tabs to our app, and we will be doing the first option, nesting a Stack Navigator in a Tab Navigator. So first, let’s install the package :

npm install @react-navigation/bottom-tabs

Now add a reference to that at the top, under where you referenced the Stack Navigator.

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

… and define the navigator, under your Stack definition.

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();

Change your main App function to this, so that we have tabs as the main navigation:

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={Home} />
        <Tab.Screen name="Details" component={Details} />
        <Tab.Screen name="Search" component={Search} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Reload your app and you’ll see your new tabs at the bottom of the screen. Note I have added one extra page called Search. You can create a method for this in the same way as we did for the Home screen, and the Details screen.

And now we need to include our Stack Navigator. We will include a Stack of pages under the Details section, so create a new method called DetailsStackScreen, that will reference each page in our Stack, like this:

function DetailsStackScreen({navigation}){
  return (
      <Stack.Navigator>
        <Stack.Screen name="Details Stack Screen" component={Details} />
        <Stack.Screen name="Further Details" component={FurtherDetails} />
      </Stack.Navigator>
  );
}

You will notice we’ve referenced a new page – Further Details, so we need to also add the method for this:

function FurtherDetails({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the FURTHER Details page</Text>
      <Button
        title="Back to the previous Screen"
        onPress={() => navigation.goBack()}
      />
      <Button
        title="Back to the HOME Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

And also we need to update our Details page to include a link to drill down to the Further Details page:

function Details({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Details page. Now you can drill down to a further details page in this Stack of screens</Text>
      
      <Button
        title="Further Details"
        onPress={() => navigation.navigate('Further Details')}
      />

      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

Finally, we need to update the main App method to reference the DetailsStackScreen instead of our original Details method :

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={Home} />
        <Tab.Screen name="Details" component={DetailsStackScreen} />
        <Tab.Screen name="Search" component={Search} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Now refresh your app to see the results, and you’ll see you have 3 tabs, each of which leads to a page. In the Details screen you will see that you can navigate through the Stack of pages you have defined.

Side navigation – also known as drawer navigation

To complete our app, we will be adding some Drawer navigation. To start we need to install the package :

npm install @react-navigation/drawer

… reference it at the top of our App.js page :

import { createDrawerNavigator } from '@react-navigation/drawer';

Then create the Drawer object :

const Drawer = createDrawerNavigator();

Now we make the main method in our App.js file reference the Drawer Navigator, which becomes the ‘wrapper’. This references each page you want to show in your side menu, like this:

export default function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="Home">
        <Drawer.Screen name="Home" component={HomeTabsScreen} />
        <Drawer.Screen name="Settings" component={SettingsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

HomeTabScreen is a new method that we need to define, that holds the TabNavigator that used to be in this main method, like this :

function HomeTabsScreen({navigation}){
  return(
    <Tab.Navigator>
         <Tab.Screen name="Home" component={Home} />
         <Tab.Screen name="Details" component={DetailsStackScreen} />
         <Tab.Screen name="Search" component={Search} />
    </Tab.Navigator>
  );
}

Then we just need to define the SettingsScreen :

function SettingsScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Settings page</Text>
      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

And finally we need to reference our styles at the bottom the page :

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

If you now run your app, you will have a fully functioning app with all three types of navigation. Drag in the Drawer Navigation menu from the left hand side and try clicking each link. You’ll notice that the Settings page does not contain any Tab Navigation, but the Home page does, so you have total control over where and how you use each type of Expo Navigation.

The app is now ready for you to build your pages and style! I’ll probably write another post on how to style the app and do things like add icons to the Tab Navigation. Feel free to email me any questions or requests for the next post at hello@brainstormcreative.co.uk!

For completeness here is the final code:

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { StyleSheet, Text, Button, View } from 'react-native';

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const Drawer = createDrawerNavigator();

function HomeTabsScreen({navigation}){
  return(
    <Tab.Navigator>
         <Tab.Screen name="Home" component={Home} />
         <Tab.Screen name="Details" component={DetailsStackScreen} />
         <Tab.Screen name="Search" component={Search} />
    </Tab.Navigator>
  );
}

function Home({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>Home Screen</Text>
      <Button
        title="Show me the Details screen"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

function DetailsStackScreen({navigation}){
  return (
      <Stack.Navigator>
        <Stack.Screen name="Details Stack Screen" component={Details} />
        <Stack.Screen name="Further Details" component={FurtherDetails} />
      </Stack.Navigator>
  );
}

function Details({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Details page. Now you can drill down to a further details page in this Stack of screens</Text>
      
      <Button
        title="Further Details"
        onPress={() => navigation.navigate('Further Details')}
      />

      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

function FurtherDetails({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the FURTHER Details page</Text>
      <Button
        title="Back to the previous Screen"
        onPress={() => navigation.goBack()}
      />
      <Button
        title="Back to the HOME Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

function Search({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Search page</Text>
      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

function SettingsScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Settings page</Text>
      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="Home">
        <Drawer.Screen name="Home" component={HomeTabsScreen} />
        <Drawer.Screen name="Settings" component={SettingsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}


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