React Native Navigation Tutorial
Tags: reactnative, javascript, beginners, mobile
Published: 2021-12-09 13:57:14

---
title: React Native Navigation Tutorial
published: true
date: 2021-12-09 13:38:31 UTC
tags: ReactNative,Javascript,Beginners,mobile
canonical_url: https://blog.shahednasser.com/react-native-navigation-tutorial/
cover_image: https://blog.shahednasser.com/static/de081a39f1737345436f7c509de3f888/nathan-da-silva-FO7kUmBYVi0-unsplash-2.jpg
---

_This article was originally published on [my personal blog](https://blog.shahednasser.com/react-native-navigation-tutorial/)_

[React Native](https://reactnative.dev) is one of the most popular cross-platform app development frameworks. Using JavaScript, you can develop native apps for both Android and iOS.

One important part of creating apps is being able to navigate between screens. In this tutorial, you'll learn how to use [React Navigation](https://reactnavigation.org) in your app to add navigation. This will include basic navigation from one screen to another, going back to the previous screen, passing parameters, listening to events, and more.

This tutorial will not explain the basics of creating a React Native app. If you're interested in learning about that, you can check out my other tutorial [React Native Tutorial: Create Your First App](https://blog.shahednasser.com/react-native-tutorial-create-your-first-app).

You can find the code for this tutorial on [this GitHub repository](https://github.com/shahednasser/react-navigation-tutorial).

## Prerequisites 

Make sure you have both [Node.js](https://nodejs.org/en/) and NPM installed on your machine. You can check if they're installed with the following command:

```
node -v
npm -v
```

If they're not installed, you can [install Node.js](https://nodejs.org/en/) and NPM will be installed automatically with it.

After that, make sure you install [Expo](https://expo.dev)'s CLI if you don't have it installed:

```
npm install -g expo-cli
```

If you're not familiar with what Expo is, Expo provides a set of tools built around React. Most importantly, it allows you to write and build your React Native app in minutes.

You should also install [Expo Go](https://expo.dev/client) on your device to be able to test the app as we go through the tutorial.

## Project Setup

Start by creating a new React Native project using Expo's CLI:

```
expo init react-navigation-tutorial —npm
```

You'll be then prompted to choose the type of app, choose "blank".

After that the `init` command will install the dependencies you need for your React Native project.

Once it's done, change to the directory of the project:

```
cd react-navigation-tutorial
```

Now, you'll install the dependencies required to use React Navigation. First, install the building blocks libraries using Expo's CLI with the following command:

```
expo install react-native-screens react-native-safe-area-context
```

Second, install the native stack navigator library:

```
npm install @react-navigation/native-stack
```

Now, you have all the libraries required to start using React Navigation.

Finally, install [React Native Paper](https://callstack.github.io/react-native-paper/index.html) to have beautifully-styled components in your app:

```
npm install react-native-paper
```

## Set Up React Navigation

Before you can start adding routes to your app, you need to create a Stack Navigator. This stack navigator will be used to create screens and navigate between them.

In `App.js`, change the content to the following:

```
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Provider as PaperProvider } from 'react-native-paper';
import HomeScreen from './screens/HomeScreen';

const Stack = createNativeStackNavigator()

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

```

Notice that in the returned value of `App`, you first have `<PaperProvider>` at the top of the elements. This is just used to make sure all screens share the same theme.

Next, you have the `<NavigationContainer>`. This component manages the navigation tree and contains the navigation state. So, it should wrap Stack navigators.

Inside `<NavigationContainer>` you have `<Stack.Navigator>`. `Stack` is created using `createNativeStackNavigator`. This function returns an object containing 2 properties: `Screen` and `Navigator`. The `Navigator` property is a React element and it should be used to wrap the `Screen` elements to manage routing configurations.

So, inside `<Stack.Navigator>` you'll have one or more `<Stack.Screen>` components. For each route, you'll have a `<Stack.Screen>` component. Now, you just have one component that points to the `Home` route.

Notice that a `Screen` component takes the `name` prop, which is the name of the route and will be referenced later on when navigating to this route, and the `component` property which is the component to render for this route.

As you can see, you're passing `HomeScreen` component to the `Home` route, so you need to create it now.

Create the directory `screens`, and inside that directory create a new file `HomeScreen.js` with the following content:

```
import React from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import { Button, Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function HomeScreen () {
  return (
    <ScrollView style={styles.scrollView}>
      <Card style={styles.card}>
        <Card.Title title="Home Screen" />
      </Card>
    </ScrollView>
  )
}

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: DefaultTheme.colors.background,
    paddingTop: 10
  },
  card: {
    width: '90%',
    marginLeft: 'auto',
    marginRight: 'auto'
  }
});

export default HomeScreen
```

This will create a basic home screen with a [ScrollView](https://reactnative.dev/docs/scrollview) component containing a [Card](https://callstack.github.io/react-native-paper/card.html) component with the title "Home Screen".

You just created your first route with React Navigation! Let's test it out.

In your terminal run to start your app:

```
npm start
```

Then, you'll be able to run the app on Expo Go on your phone by scanning the QR code on the Expo Go app on Android or on the Camera app on iOS.

Once the app run, you'll see the Home screen that you created as it's the default and only route.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1545.PNG)

## Navigate to Another Screen

In this section, you'll learn how to navigate from one screen to another.

Screens that are inside the Stack Navigation, like HomeScreen in this app, receive a `navigation` prop. This prop allows us to navigate to other screens in the app.

Let's first create the screen you'll navigate to. Create the file `screens/BookScreen.js` with the following content:

```
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function BookScreen () {
  return (
    <View style={styles.container}>
      <Card style={styles.card}>
        <Card.Title title="This is Books Screen" />
      </Card>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: DefaultTheme.colors.background,
    alignItems: 'center',
    paddingTop: 10
  },
  card: {
    width: '90%'
  }
});

export default BookScreen;
```

This screen is similar to `HomeScreen`. It just shows a card with the title "This is Books Screen".

Next, add the new route in `App.js` for `BookScreen` below the "Home" route:

```
<Stack.Screen name="Book" component={BookScreen} />
```

Don't forget to import `BookScreen` below the imports at the beginning of `App.js`:

```
import BookScreen from './screens/BookScreen';
```

Now, you can navigate to the "Book" route inside this stack navigation. To see how it works, you'll add a button in `HomeScreen` that when the user clicks will navigate to `BookScreen`.

In `HomeScreen`, add the `navigation` prop to the function:

```
function HomeScreen ({ navigation })
```

Then, change the returned value of the function to the following:

```
return (
    <ScrollView style={styles.scrollView}>
      <Card style={styles.card}>
        <Card.Title title="Navigate to 'Book' Screen" />
        <Card.Content>
          <Button mode="contained" onPress={() => navigation.navigate('Book')}>
            Navigate
          </Button>
        </Card.Content>
      </Card>
    </ScrollView>
  )
```

You change the title of the card to "Navigate to 'Book' Screen". Then, inside the content of the card, you add a [Button](https://callstack.github.io/react-native-paper/button.html) component with `onPress` listener. This listener will be executed when the user presses on the button.

Inside the listener, you use the `navigation` prop to navigate to the `Book` screen using the method `navigate`. The method `navigate` takes the name of the route to navigate to.

Let's test it out. Run the app again if it isn't running. You should see a new button on the Home screen.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1543.PNG)

Try clicking on the `Navigate` button. You'll be navigated to the `BookScreen`.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1544.PNG)

Notice how the back button in the navigation bar is added automatically when you navigate to another screen. You can use it to go back to the previous screen, which is in this case the Home screen.

## Navigate with Parameters

In a lot of cases, you'll need to navigate to another screen and pass it parameters. In this section, you'll create an input that allows the user to enter their name, then when they submit you'll open a new screen called `NameScreen` which will show a greeting to the user with the name they entered.

Start by adding a new state variable to hold the value of the input you'll add soon in `HomeScreen.js`:

```
const [name, setName] = useState('');
```

Make sure to add an import for `useState` at the beginning of the file:

```
import React, { useState } from 'react';
```

Then, add a new Card component below the existing one:

```
<Card style={styles.card}>
    <Card.Title title="Navigate with Parameters" />
    <Card.Content>
        <TextInput mode="outlined" label="Name" value={name} onChangeText={(text) => setName(text)} style={styles.textInput} />
            <Button mode="contained" disabled={name.length === 0} onPress={() => navigation.navigate('Name', { name })}>
                Navigate
    	</Button>
    </Card.Content>
</Card>
```

This new card has a [TextInput](https://callstack.github.io/react-native-paper/text-input.html) with the value `name`, and on the `onChangeText` event, which occurs when the user makes changes to the text inside the input, you change the value of the `name` state variable.

Below the input, you have a button that is disabled when the `name` state variable is empty. You also add an `onPress` event listener which navigates the user to the `Name` route.

Notice that you're using the same `navigation.navigate` method that you used before to navigate to the "Book" route, however, this time you pass a second parameter to the method. This method accepts as a second parameter an object of parameters you want to pass. Here, you pass the `name` variable inside the object.

One last thing you need to do in the `HomeScreen` is change the `styles` object to the following:

```
const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: DefaultTheme.colors.background,
    paddingTop: 10
  },
  card: {
    width: '90%',
    marginLeft: 'auto',
    marginRight: 'auto',
    marginBottom: 10
  },
  textInput: {
    marginBottom: 10
  }
});
```

This just makes some changes to the `card` property and adds a new property `textInput`.

You'll now create the `NameScreen` which will be the component for the "Name" route you'll add soon. Create `screens/NameScreen.js` with the following content:

```
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function NameScreen ({ route }) {
  const { name } = route.params;

  return (
    <View style={styles.container}>
      <Card style={styles.card}>
        <Card.Title title={`Hello, ${name}`} />
      </Card>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: DefaultTheme.colors.background,
    alignItems: 'center',
    paddingTop: 10
  },
  card: {
    width: '90%'
  }
});

export default NameScreen;
```

This screen is essentially the same as `BookScreen`, however, notice the `route` prop passed to the function.

As mentioned before, the components inside the navigation stack receive a `navigation` prop to navigate between screens. They also receive a `route` prop which you can use to get the parameters passed to the screen using `route.params`.

So, in `NameScreen`, you retrieve the value entered in the `Name` input in the `HomeScreen`, which is passed when navigating to the `NameScreen` when the button is clicked using `route.params`:

```
const { name } = route.params;
```

You then show the user a greeting inside a card using the name parameter.

One last thing left to do is add the "Name" route to the navigation stack. Add a new `<Stack.Screen>` below the previous ones in `App.js`:

```
<Stack.Screen name="Name" component={NameScreen} />
```

And import `NameScreen` below other imports at the beginning of the file:

```
import NameScreen from './screens/NameScreen';
```

Let's test it out. Run the app if it isn't already running. You'll see that there's a new card on the Home screen with an input and a button.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1546.PNG)

Try entering your name, then click the "Navigate" button below the input. You'll be navigated to the `NameScreen` and you'll see your name.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1547.PNG)

You can try going back then changing the value of the name. The name in the `NameScreen` will change accordingly.

## Configure the Header

### Change the title

Sometimes, you want the title of a route to be different than the name of the route, or you want the title to be dynamic based on a parameter passed or some other logic.

In this section, you'll add a new input in `HomeScreen` that will let you to enter a title, then on clicking the navigate button you'll be navigated to a new screen `TitleScreen`, whose title will change based on the title entered in the input in HomeScreen.

Start by adding a new state variable in `HomeScreen.js` to store the title:

```
const [title, setTitle] = useState('');
```

Then, add a new card below the previous cards:

```
<Card style={styles.card}>
        <Card.Title title="Navigate to Route with Title" />
        <Card.Content>
          <TextInput mode="outlined" label="Title" value={title} onChangeText={(text) => setTitle(text)} style={styles.textInput} />
          <Button mode="contained" disabled={title.length === 0} onPress={() => navigation.navigate('Title', { title })}>
            Navigate
          </Button>
        </Card.Content>
      </Card>
```

This is pretty much the same as the card we added in the previous section. The only difference is that it uses the `title` state variable, and the listener for `onPress` for the button navigates to the route "Title", passing the `title` as a parameter.

Next, create the file `screens/Title.js` with the following content:

```
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function TitleScreen () {
  return (
    <View style={styles.container}>
      <Card style={styles.card}>
        <Card.Title title="This is title screen" />
      </Card>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: DefaultTheme.colors.background,
    alignItems: 'center',
    paddingTop: 10
  },
  card: {
    width: '90%'
  }
});

export default TitleScreen;
```

This screen has nothing special. It just shows a card with the title "This is title screen". It doesn't even use the title parameter.

That's because you can change the title of a screen by passing an `options` parameter to `<Stack.Screen>` when adding the route.

In `App.js`, add an import for `TitleScreen` below other imports at the beginning of the file:

```
import TitleScreen from './screens/TitleScreen';
```

Then, add the new route below previous `<Stack.Screen>`:

```
<Stack.Screen name="Title" component={TitleScreen} options={({route}) => ({title: route.params.title})} />
```

Every `Stack.Screen` component can take an `options` prop. The `options` prop can be an object like so:

```
options={{title: "Hello"}}
```

This is enough if your options are static. However, if the value for any of the options is dynamic, like in this example, you can instead pass it a function that returns an object. This function can receive as a parameter `route`, which is similar to the `route` parameter you used in `NameScreen`:

```
options={({route}) => ({title: route.params.title})}
```

In this function, you return an object that has a `title` property with the value `route.params.title`. So, when the user enters a title in the input and clicks on the Navigate button, the title will be passed to the route, which will change the title of "Title" route using the function passed to the `options` prop.

Let's test it out. Run the app if it's not running already. You should see a new card on the Home screen with a new input:

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1548.PNG)

Try entering any title you want in the input then click on Navigate. You'll see that you'll be navigated to the `TitleScreen`, but the title will be the value you entered in the input.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1549.PNG)

You can try going back then changing the value entered in the input. The title of the screen will change accordingly.

### Add Header Button

Another option you can add is header buttons. You can customize what your header shows on the left and right by using the `headerRight` and `headerLeft` properties in the `options` param of `<Stack.Screen>`.

In this section, you'll add a button to the right of the header of the Home screen which will show a user an alert when they click on it.

In `App.js`, add to the "Home" route a prop `option`:

```
<Stack.Screen name="Home" component={HomeScreen} options={{
            headerRight: () => (
              <IconButton icon="alert-outline" onPress={() => alert('You\'re awesome!')} color={DefaultTheme.colors.notification} />
            )
}} />
```

In the `options` prop, you pass an object with the property `headerRight`. The `headerRight` property can be a component that you can render elements inside. You render an [IconButton](https://callstack.github.io/react-native-paper/icon-button.html) component, which is a button that only has an icon without text. In the `onPress` event listener, you show an alert to the user.

That's all. Run the app if it isn't running already. You'll see a new icon at the top right of the header in Home Screen.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1550.PNG)

Click on it and you'll see an alert.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1551.PNG)

## Navigation Events

In React Navigation, you can subscribe to two events: `focus` and `blur`. The `focus` event will occur every time the screen is opened and is currently the main screen. The `blur` event will occur whenever a screen was in focus but navigation occurs that makes the screen not the current main screen. Simply put, the `focus` event is when the screen is visible to the user, and the `blur` event occurs when a screen was visible to a user but isn't anymore.

In this section, you'll add a counter that will count how many times you navigated to other screens from the home screen. So, this counter will increment in the `blur` event.

To subscribe to events, in a `useEffect` callback inside a component, you can use `navigation.addListener` passing it the name of the event as a first parameter, and the event handler as a second parameter. The `addListener` method returns an unsubscribe function which you should return in the `useEffect` callback.

In `HomeScreen.js`, add an import for `useEffect` at the beginning of the file:

```
import React, { useEffect, useState } from 'react';
```

Then, add a new state variable `counter` inside the `HomeScreen` component:

```
const [counter, setCounter] = useState(0);
```

After that add the `useEffect` callback that will register the event handle for the `blur` event:

```
useEffect(() => {
    return navigation.addListener('blur', () => {
      setCounter(counter + 1);
    });
  });
```

As you can see, you use `navigation.addListener` to add an event listener to the `blur` event. The function passed as a second parameter is the handler of the event. It will be executed whenever the screen is out of focus (not the screen visible to the user). Inside the event handler, you increment the counter by 1.

Finally, you'll show the counter at the top of the screen. In `ScrollView`, add a new card before the previously added cards:

```
<Card style={styles.card}>
	<Card.Title title={`Navigation Count: ${counter}`} />
</Card>
```

Let's test it out. Run the app if it's not already running. You should see a card with a count of navigation at the top of the screen.

## Go Back

The last thing you'll learn in this tutorial is how to go back to the previous screen. As you've seen throughout the tutorial, when you navigate to a screen you'll see a back button in the header which you can use to go back to the previous screen.

Although this is sufficient in most cases, sometimes you want to go back to the previous screen programmatically. You'll create in this section a new screen `BackScreen` which you can go to from the `HomeScreen`. This screen will have a back button in its content and when you click on it you can go back to the previous screen, which is the `HomeScreen`.

Create the file `screens/BackScreen.js` with the following content:

```
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Button, Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function BackScreen ({ navigation }) {
  return (
    <View style={styles.container}>
      <Card style={styles.card}>
        <Card.Title title="This is Back Screen" />
        <Card.Content>
          <Button mode="contained" onPress={() => navigation.goBack()}>
            Go Back
          </Button>
        </Card.Content>
      </Card>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: DefaultTheme.colors.background,
    alignItems: 'center',
    paddingTop: 10
  },
  card: {
    width: '90%'
  }
});

export default BackScreen;
```

This screen is pretty much the same as other screens. The things you should note is that, first, the screen has uses the `navigation` prop that is passed to components inside the navigation stack. Second, the screen has a button inside a card which, on press, will use the `navigation` prop to go back using the `goBack` method:

```
<Button mode="contained" onPress={() => navigation.goBack()}>
```

Now, go to the `HomeScreen` and add a new card at the end of the ScrollView:

```
<Card style={styles.card}>
    <Card.Title title="Navigate to 'Back' Screen" />
    <Card.Content>
        <Button mode="contained" onPress={() => navigation.navigate('Back')}>
            Navigate
    	</Button>
    </Card.Content>
</Card>
```

This card just shows a button to navigate to the route "Back". Let's add that route now.

In `App.js` add a new `<Stack.Screen>` component below the previously added ones:

```
<Stack.Screen name="Back" component={BackScreen} />
```

It's ready now. Run the app if it isn't already running. You'll see a new card at the end of the list.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1554.PNG)

Click on "Navigate" on the last card. You'll be navigated to the `BackScreen`.

![React Native Navigation Tutorial](https://backend.shahednasser.com/content/images/2021/12/IMG_1555.PNG)

Click on the "Go Back" button in the card. You'll be taken back to the `HomeScreen`.

## Conclusion

In this tutorial, you learned how to use React Navigation to navigate between screens, pass a parameter from one screen to another, configure the header of a screen, add navigation event listeners, and go back programmatically to the previous screen.

Although this covers most use cases for using React Navigation, be sure to check out [their documentation](https://reactnavigation.org/docs/getting-started) for more details on how to use it.