How to Set Up and Use Navigators in React Native
Tags: reactnative, javascript, mobile
Published: 2020-07-17 14:32:17

---
title: How to Set Up and Use Navigators in React Native
published: true
description: React Native navigators are used to quickly set up routing of screens. In this tutorial, we fetch data using GraphQL and then pass it between two screens.
tags: reactnative, javascript, mobile
canonical_url: https://blog.jscrambler.com/how-to-set-up-and-use-navigators-in-react-native/
cover_image: https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators.jpg
---

[React Navigation](https://reactnavigation.org/) released its 5th stable version of the library a few months back. Even though the lib is just a little over two years old, it is without a doubt one of the most popular navigation solutions in React Native apps that also has support for the Expo SDK.

The major highlight of this new release version is that routing of screens is now based on component configuration.

In this tutorial, let's take a look at how to set up and use a stack navigation pattern between two screens, and pass data from one screen to another. The data is going to be fetched from a third-party API using GraphQL query language. This is possible using the [Apollo client](https://www.apollographql.com/docs/react/), which allows us to fetch results from a REST endpoint.

## Prerequisites

To follow this tutorial, please make sure you have the following installed on your local dev environment:

- [Node.js](https://nodejs.org/) version >= `12.x.x` installed
- JavaScript/ES6 basics
- Have access to one package manager such as npm or yarn
- [expo-cli](https://github.com/expo/expo-cli) version installed or use npx

The demonstrated example is based on Expo SDK 38.

## Install dependencies

To start, generate a new Expo project with a `blank` template by running the following command in a terminal window:

```shell
npx expo init [Project Name]

# after the project directory has been generated

cd [Project Name]
```

Then, install the dependencies below for the `react-navigation` library to work. The first command is going to install the core packages of `react-navigation`. These core packages are used by navigators to create the navigation structure in the app.

The second command uses `expo install` instead of `npm install` or `yarn add`. The reason is that expo is going to install the version of the libraries mentioned that are compatible with the Expo SDK. This second command installs the peer dependencies that the  `react-navigation` library depends on.

```shell
yarn add @react-navigation/native @react-navigation/stack

# use expo install for Expo projects only
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
```

Do note that the package `@react-navigation/stack` is only required to install when you are going to use the Stack navigation pattern in the app. For example, if you are just going to use tab navigation, you are going to install a different package as shown [here](https://reactnavigation.org/docs/en/material-bottom-tab-navigator.html).

## What is a stack navigator?

The stack navigation pattern allows transitioning from one screen of the app to another while managing the navigation history. If the app uses only one stack navigator, then it is conceptually similar to how a web browser handles navigation state. The app pushes and pops screens from the navigation stack as users interact with it, and this results in the user seeing different screens.

Start by creating a new directory `src/navigation/` and inside it create a new file called `MainStackNavigator.js` with the following import statements.

```js
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
```

From the above snippet, the `NavigationContainer` is a component that manages the navigation tree. It contains the navigation state and it has to wrap the structure of all navigators.

The `createStackNavigator` is a function that is used to implement a stack navigation pattern. This function returns two React components: `Screen` and `Navigator` that help to configure each component screen.

Since the app does not have any screen components for now, in the next section let us create both the screens the app requires using some mock data to display.

## Create app screens

Start by creating two screen component files called `Home.js` and `Details.js` inside the directory `src/screens/` with the following code snippets:

```js
// src/screens/Home.js
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';

export default function Home() {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Home Screen</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#ebebeb'
  },
  text: {
    color: '#333',
    fontSize: 24,
    fontWeight: 'bold'
  }
});
```

```js
// src/screens/Details.js
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';

export default function Details() {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Details Screen</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#ebebeb'
  },
  text: {
    color: '#333',
    fontSize: 24,
    fontWeight: 'bold'
  }
});
```

The stack navigator needs screen components as routes. These routes are available in the form of screen components. Import these two screen components inside the `MainStackNavigator.js` file and then create the Stack navigator function.

```js
// other import statements

import Home from '../screens/Home';
import Details from '../screens/Details';

const Stack = createStackNavigator();

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

export default MainStackNavigator;
```

In the above snippet, there are two required props with each `Stack.Screen`. The prop name refers to the `name` of the route and the prop `component` specifies which screen to render at the particular route. The order of the screens matters, as the first screen defined in the stack navigator pattern is going to be the bottom of the stack.

Import this navigator inside the `App.js` component.

```js
import React from 'react';
import MainStackNavigator from './src/navigation/MainStackNavigator';

export default function App() {
  return <MainStackNavigator />;
}
```

To check if the configuration is working, start the development server with `expo start` and then open the app either on a real device or in a simulator as shown below.

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-1.png" alt="React Native Navigators Screen 1"></center>

## Specifying options for each screen in Stack Navigator

By default, the title shown on each screen is the same as the value provided on the `name` attribute for each screen component in the stack navigator. However, you can set the title of the screen. Let us change the title of the screen shown, from “Home” to “Crypto List”.

This is done by specifying the options on each screen as shown below. Open the `MainStackNavigator.js` file and the prop options on `Stack.Screen` for the `Home` component.

```js
<Stack.Screen name="Home" component={Home} options={{ title: 'Crypto List' }} />
```

The changes are instantly reflected in the Expo client.

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-2.png" alt="React Native Navigators Screen 2"></center>

## Navigating between two screens

Open `screens/Home.js` and add a button component that is going to navigate from the `Home` screen component to the `Details` screen when pressed.

Import `TouchableOpacity` from `react-native` and make sure to use the `navigation` prop passed to the `Home` screen. This prop is passed to every screen that is a route wrapped by the current Stack Navigator in the app.

```js
import React from 'react';
import { StyleSheet, View, Text, TouchableOpacity } from 'react-native';

export default function Home({ navigation }) {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Home Screen</Text>
      <TouchableOpacity
        style={styles.buttonContainer}
        onPress={() => navigation.navigate('Details')}
      >
        <Text style={styles.buttonText}>Go to Detail Screen</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#ebebeb'
  },
  text: {
    color: '#333',
    fontSize: 24,
    fontWeight: 'bold'
  },
  buttonContainer: {
    backgroundColor: '#222',
    borderRadius: 5,
    padding: 10,
    margin: 20
  },
  buttonText: {
    fontSize: 20,
    color: '#fff'
  }
});
```

Here is the output you are going to get after this step:

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-3.png" alt="React Native Navigators Screen 3"></center>

When the user presses the button on the Home screen, the navigator will direct the user to the `Details` screen.

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-4.gif" alt="React Native Navigators Screen 4"></center>

## Using screen options to modify the header

You can use the `screenOptions` prop to apply common styles to the header across the navigator. For example, in the code snippet below, let us set the properties, `headerStyle`, `headerTintColor`, and `headerTitleStyle` to change the background color of all screen headers as well as the color of the title on each screen.

- `headerStyle` is a style object that can be used to set the background color of the header for the screen component;
- `headerTitleStyle` is another style object that allows you to customize the title or the text of the header;
- `headerTintColor` is the color property for both the back button and the title of the header.

Open the `src/navigation/MainStackNavigator.js` file to make these changes.

```js
<Stack.Navigator
        screenOptions={{
          gestureEnabled: true,
          headerStyle: { backgroundColor: 'tomato' },
          headerTitleStyle: { fontWeight: 'bold' },
          headerTintColor: '#f8f8f8'
        }}
      >
```

Here is the output:

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-5.png" alt="React Native Navigators Screen 5"></center>

With the basic configuration of a stack navigator working, let us now fetch the data from a third-party API using the Apollo client in the next section.

## Install Apollo dependencies

Let's install all the required dependencies to integrate the Apollo client and request the REST endpoint using GraphQL queries:

```shell
yarn add apollo-client apollo-cache-inmemory graphql-tag apollo-link-rest apollo-link graphql graphql-anywhere qs @apollo/react-hooks
```

## Configure the Apollo client in React Native

In this section, let us integrate the Apollo client so that we can fetch the data from the REST endpoint. Start by creating a new directory `src/graphql` and, inside it, also create a new file `Client.js`.

The `apollo-client` package along with `apollo-cache-inmemory` and `apollo-link` is a fully-featured GraphQL client that can be integrated into React or React Native apps. Let us import all three of them inside this file:

```js
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { RestLink } from 'apollo-link-rest';
```

For demo purposes, the API endpoint will be used as a REST endpoint from [CryptoCompare.com](https://www.cryptocompare.com/). Make sure, at this point, that you have access to the API Key (that is free at the time of writing this tutorial). Their API offers many endpoints for different use cases but we are going to fetch several top coins by their total volume across all markets in the last 24 hours.

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-6.png" alt="React Native Navigators Screen 6"></center>

Add a `RestLink` for the REST API endpoint and pass `headers`, which is an object representing values to be sent as headers on the request:

```js
const restLink = new RestLink({
  uri: 'https://min-api.cryptocompare.com',
  headers: {
    Authorization:
      'd251970548f7321b548d3fb61d58c1a456974ea02ba41437fc9bf711f4e89782'
  }
});
```

Add the following configuration with the default cache and `RestLink` to complete the configuration of the Apollo client:

```js
export const client = new ApolloClient({
  link: restLink,
  cache: new InMemoryCache()
});
```

Now, open the `App.js` file to wrap the current stack navigator with `ApolloProvider`. This provider is similar to React's `Context.Provider` and places the Apollo client in the context. This makes them accessible to the Apollo client easily and from anywhere inside the component tree.

```js
import React from 'react';
import MainStackNavigator from './src/navigation/MainStackNavigator';

import { ApolloProvider } from '@apollo/react-hooks';
import { client } from './src/graphql/Client';

export default function App() {
  return;
  <ApolloProvider client={client}>
    <MainStackNavigator />
  </ApolloProvider>;
}
```

## Writing your first GraphQL query

In this section, let us write a query to hook the Apollo client to fetch results from the REST API endpoint. However, the query is going to be made in GraphQL query language with the help of `graphql-tag`.

In the `src/graphql/` directory, create a new file called `Queries.js` and import `graphql-tag`. Then, create a query to fetch data. This query is called `FETCH_COIN_LIST` and is defined using a template from the `gql` tag. Using the `@rest` directive, Apollo manages the parsing of the query from a REST endpoint to the GraphQL API.

```js
import gql from 'graphql-tag';

export const FETCH_COIN_LIST = gql`
  query FetchCoinsList {
    coinsList
      @rest(type: "ListPayload", path: "/data/top/totalvolfull?tsym=USD") {
      Data @type(name: "DataPayload") {
        CoinInfo @type(name: "CoinInfoPayload") {
          Id
          Name
          FullName
        }
        DISPLAY @type(name: "DisplayPayload") {
          USD @type(name: "USDPayLoad") {
            PRICE
            OPENDAY
            HIGHDAY
            LOWDAY
            OPEN24HOUR
          }
        }
      }
    }
  }
`;
```

## Make a request to REST endpoint with the Apollo client

Open the file `screens/Home.js` and import the `FETCH_COIN_LIST` query as well as the `useQuery` hook from `@apollo/react-hooks`.

The React hook `useEffect` is used below to test that the endpoint is fetching data as per our needs. The data fetched is going to be displayed in a console statement.

The hook `useQuery` is used to request the API endpoint by referencing the query `FETCH_COIN_LIST`. After being called, it returns a result object with a set of properties. We only need two properties for now: loading and data. De-structure this query hook inside the `Home` component as shown below.

```js
import React, { useEffect } from 'react';
import { useQuery } from '@apollo/react-hooks';

import { StyleSheet, View, Text, TouchableOpacity } from 'react-native';
import { FETCH_COIN_LIST } from '../graphql/Queries';

export default function Home({ navigation }) {
  const { loading, data } = useQuery(FETCH_COIN_LIST);

  useEffect(() => {
    console.log(data);
  }, []);

  return (
    <View style={styles.container}>
      <Text style={styles.text}>Home Screen</Text>
    </View>
  );
}

// ... rest remains same
```

---

**Sidenote:** Don't forget that you should always protect your source code in commercial and enterprise apps to prevent tampering. For more details, follow <a href="https://blog.jscrambler.com/how-to-protect-react-native-apps-with-jscrambler/?utm_source=dev.to&utm_medium=referral&utm_campaign=react-native-navigators">this guide</a>. 

---

To see the result, make sure the `expo start` command is running from the terminal window. Then, go to the Expo client either on a real device or a simulator and open the developer menu on a Mac using:

- if on iOS simulator, press `Ctrl-Cmd-Z`
- if on Android emulator, press `Cmd+M`
- if using a real device, just shake your device a bit

This is what the developer menu in an Expo client looks like:

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-7.png" alt="React Native Navigators Screen 7"></center>

Choose the option `Debug Remote JS`. A debugger like below should appear in your default web browser.

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-8.png" alt="React Native Navigators Screen 8"></center>

Open the `Console` tab from the `Developer Tools` of the web browser. You are going to get the following result.

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-9.png" alt="React Native Navigators Screen 9"></center>

That's it! The Apollo integration is working and you can start displaying the data in the app.

## Add an Activity Indicator while fetching results

The `useQuery` hook gives one property called “loading” that can be used to indicate on the device's screen when the query is in the process of fetching the result. Using the `ActivityIndicator`, a loading indicator can be displayed.

Import the `ActivityIndicator` component from `react-native` in `Home.js`.

```js
export default function Home({ navigation }) {
  const { loading, data } = useQuery(FETCH_COIN_LIST);

  if (loading && !data) {
    return (
      <View style={styles.loadingIndicatorContainer}>
        <ActivityIndicator size="large" color="#fff" />
      </View>
    );
  }
  return (
    <View style={styles.container}>
      <Text style={styles.boldText}>Coins List</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#333',
    justifyContent: 'center',
    alignItems: 'center'
  },
  boldText: {
    color: '#fff',
    fontSize: 24,
    fontWeight: 'bold'
  },
  loadingIndicatorContainer: {
    flex: 1,
    backgroundColor: '#333',
    justifyContent: 'center',
    alignItems: 'center'
  }
});
```

## Display data in a list using FlatList

To display a list of items, let us create a separate component that can be reused for a different purpose if the scope of this app gets larger. Create a new directory called `src/components` and inside it place a new file `ListItem.js`.

This component is going to display the name, full name, and the price of the component, all inside a touchable button that is going to navigate to the `Details` screen you created earlier.

With some destructuring from the incoming props coin (_which is going to be passed from `Home.js`_), add a functional component called `ListItem`.

```js
import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';

export default function ListItem(props) {
  const { coin, onPress } = props;
  const { CoinInfo, DISPLAY } = coin;
  const { FullName, Name } = CoinInfo;

  return (
    <TouchableOpacity
      style={styles.container}
      onPress={() => onPress && onPress(coin)}
    >
      <View style={styles.row}>
        <Text style={styles.text} numberOfLines={1}>
          {Name}
        </Text>
        <View style={styles.right}>
          <Text style={styles.text} numberOfLines={1}>
            {DISPLAY.USD.PRICE}
          </Text>
        </View>
      </View>

      <View style={styles.row}>
        <Text style={[styles.text, styles.name]} numberOfLines={1}>
          {FullName}
        </Text>
      </View>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20
  },
  active: {
    backgroundColor: 'rgba(255,255,255,0.05)'
  },
  row: {
    flexDirection: 'row',
    justifyContent: 'space-between'
  },
  right: {
    flex: 1,
    alignSelf: 'flex-end',
    alignItems: 'flex-end'
  },
  text: {
    color: '#FFFFFF',
    fontSize: 24,
    fontWeight: '500'
  },
  name: {
    color: 'rgba(255,255,255,0.5)',
    fontSize: 16,
    fontWeight: '300'
  }
});
```

Now, import this component in the `Home.js` file. Also, import `FlatList` from `react-native` core.

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

import ListItem from '../components/ListItem';
//...
```

Next, add this `FlatList` component wrapped inside the root `View` component like below.

```js
<View style={styles.container}>
  <FlatList
    contentContainerStyle={styles.contentContainerStyle}
    data={data.coinsList.Data}
    keyExtractor={item => item.CoinInfo.Id.toString()}
    renderItem={({ item }) => {
      return (
        <ListItem
          coin={item}
          onPress={() => navigation.navigate('Details', { coin: item })}
        />
      );
    }}
  />
</View>
```

Here is the output after this step:

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-10.png" alt="React Native Navigators Screen 10"></center>

You are also going to see the initial loading screen.

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-11.gif" alt="React Native Navigators Screen 11"></center>

## Passing the data between two screens

Since all the props are being passed from the `Home` to the `Details` screen and the navigation pattern is working, let us set up the `Details` screen now. Once `route.params` is de-structured into an object, you can use the values from that object to get the data passed from the `Home` screen.

```js
export default function Details(props) {
  const { route } = props;
  const { params } = route;
  const { coin } = params;
  const { CoinInfo, DISPLAY } = coin;
  const { FullName, Name } = CoinInfo;
  const { USD } = DISPLAY;
  const { PRICE, OPENDAY, HIGHDAY, LOWDAY, OPEN24HOUR } = USD;

  return (
    <View style={styles.container}>
      <View style={styles.header}>
        <Text numberOfLines={1} style={styles.text}>
          {Name} - {FullName}
        </Text>
        <Text style={styles.priceText} numberOfLines={1}>
          Price: {PRICE}
        </Text>
      </View>
      <View style={styles.statsContainer}>
        <View>
          <View style={styles.statRow}>
            <Text style={styles.stat} numberOfLines={1}>
              Open Day
            </Text>
            <Text style={styles.stat} numberOfLines={1}>
              {OPENDAY}
            </Text>
          </View>
          <View style={styles.statRow}>
            <Text style={styles.stat} numberOfLines={1}>
              Highest in a day
            </Text>
            <Text style={styles.stat} numberOfLines={1}>
              {HIGHDAY}
            </Text>
          </View>
          <View style={styles.statRow}>
            <Text style={styles.stat} numberOfLines={1}>
              Lowest in a day
            </Text>
            <Text style={styles.stat} numberOfLines={1}>
              {LOWDAY}
            </Text>
          </View>
          <View style={styles.statRow}>
            <Text style={styles.stat} numberOfLines={1}>
              Open in 24 hours
            </Text>
            <Text style={styles.stat} numberOfLines={1}>
              {OPEN24HOUR}
            </Text>
          </View>
        </View>
      </View>
    </View>
  );
}
```

Also, add the corresponding styles to this component:

```js
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff'
  },
  header: {
    flex: 30,
    justifyContent: 'center',
    alignItems: 'center'
  },
  text: {
    fontSize: 32,
    color: '#161616'
  },
  priceText: {
    fontSize: 24,
    color: '#161616'
  },
  statsContainer: {
    flex: 62,
    backgroundColor: '#161616'
  },
  statRow: {
    padding: 10,
    flexDirection: 'row',
    justifyContent: 'space-between'
  },
  stat: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '500'
  }
});
```

On visiting the details of any coin in the list, the following is going to be displayed.

<center><img src="https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-react-native-navigators-12.png" alt="React Native Navigators Screen 12"></center>

## Conclusion

In this tutorial, we have discussed many strategies and properties that you can apply and implement in your Stack navigator. The first objective is to get familiar with the component-based configuration of the Stack Navigator in the latest version of the `react-navigation` library.

The second objective is also fulfilled, which is to use the REST endpoint and integrate the Apollo client into any API endpoint to query desired results in a React Native and Expo app and pass the data between two screens.

Finally, don't forget to pay special attention if you're developing commercial React Native apps that contain sensitive logic. You can protect them against code theft, tampering, and reverse engineering by following <a href="https://blog.jscrambler.com/how-to-protect-react-native-apps-with-jscrambler/?utm_source=dev.to&utm_medium=referral&utm_campaign=react-native-navigators">this guide</a>.