React Native Essentials: Getting started with React Navigation

React Native Essentials : Navigating between screens with React Navigation

In this article of our series “React Native Essentials”, we will dive into how to navigation between screens in a React Native app using React Navigation.

React Navigation is a widely adopted navigation solution in the React Native ecosystem. If you’re new to the world of React Native, or even if you’ve been around for a while but haven’t had the chance to dive deep into its navigation capabilities, you’re in the right place!

Before React Navigation came into the picture, navigating between screens in a React Native application could feel like a Herculean task. Trust me, I’ve been there. I remember when I was just starting out with React Native, making an app transition from one screen to another felt like trying to solve a complex puzzle. But then, React Navigation came to the rescue and saved us all.

React Navigation is a JavaScript-based library that provides a way for your app to transition between screens, similar to how you would navigate between pages on a website. With a simple and consistent API, it makes the process of managing and implementing screen transitions in your React Native apps a breeze.

In the next sections, we’ll explore why you should consider using React Navigation, how to get it set up in your project, and how to start navigating between screens with ease. So, buckle up and get ready for a fun ride through the world of React Navigation!

Why Use React Navigation?

You might be wondering, “Why should I use React Navigation? Aren’t there other navigation libraries out there?” Well, you’re absolutely correct. There are indeed other options available for navigation in React Native, but let me share with you why React Navigation has become my go-to choice, and why it might be the right fit for your projects too.

Firstly, React Navigation is fully written in JavaScript, which aligns well with the rest of your React Native codebase. This means you can leverage your existing knowledge of JavaScript to understand and control your app’s navigation flow.

Secondly, React Navigation provides a highly customizable and flexible API. Whether you want to create a stack of screens, tabs, or a drawer sidebar — React Navigation has got you covered. Plus, it allows for seamless integration with other libraries in the React ecosystem.

Lastly, and my personal favorite, is the active and vibrant community behind React Navigation. The documentation is always up to date, and there are plenty of tutorials and guides available to help you get unstuck.

Setting Up React Navigation in Your Project

Before we begin, make sure you have a React Native project ready to go. If you’re unsure about this, check out the React Native documentation for a quick guide on setting up a new project.

Alright, let’s dive in:

Step 1: Install React Navigation

First, we need to install the @react-navigation/native package. Open up your terminal, navigate to your project directory, and run the following command:

npm install @react-navigation/native

Step 2: Install Dependencies

React Navigation relies on some additional dependencies that we need to install. For a bare React Native project, you need to install the following libraries:

  • If you have a Expo managed project : npx expo install react-native-screens react-native-safe-area-context
  • If you have a bare React Native project :
    bash npm install react-native-screens react-native-safe-area-context

Step 3: Install Navigators

Now, we install the navigators that we will use in our project. For this guide, we will be using the stack navigator, so let’s install it:

npm install @react-navigation/stack

Step 4: Finalize Installation

If you’re using Expo, you are already set!

If you’re on a Mac and developing for iOS, make sure to install the pods:

cd ios && pod install && cd ..

Step 5: Set up the NavigationContainer

Next, import the necessary components at the top of your main app file (usually App.js or index.js):

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

After that, we need to wrap our app in the NavigationContainer component. This component manages our app’s navigation state and links it to the React context:

export default function App() {
  return (
    <NavigationContainer>
      {/* Your app code will go here */}
    </NavigationContainer>
  );
}

And voilà, React Navigation is now set up in your project!

Don’t worry if this feels a little overwhelming right now. As we delve deeper into the world of React Navigation, all these pieces will start to come together. In the next section, we’ll dive straight into navigating between screens, which is where the fun really begins!

Basics of Navigating Between Screens

Let’s start by understanding the core concepts of React Navigation:

  • Screen: In React Navigation, a screen corresponds to a React Component. Each screen represents a standalone part of your app’s interface, and it’s where your users will interact with your app.
  • Navigator: Navigators are what allow us to transition between screens. They maintain a history (or a ‘stack’) of screens and manage the transition animations when moving between these screens.
  • Routes and parameters: When navigating to a screen, we can pass parameters to it. These parameters can be used to customize the screen or pass data, like you would on the Web with URL parameters.

Now, let’s put these concepts into action with a simple example:

NOTE : In these examples, we are using the Stack Navigator to host our screens. Don’t worry, we will explain in details what is a Stack Navigator in the next section.

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

// Define your screens
function HomeScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

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

// Create a stack navigator
const Stack = createStackNavigator();

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

export default App;

In this example, we’ve created two screens, HomeScreen and DetailsScreen. Each screen registered in the navigator receives a navigation prop and a route prop.

In HomeScreen, we have a button that, when pressed, navigates to the DetailsScreen using the navigation.navigate function from the navigation prop.

In the next section, we’ll explore the stack navigator in more detail, understand how it maintains a stack of screens, and discover how we can manipulate this stack to control our app’s navigation flow.

Deep Dive: The Stack Navigator

Now, it’s time to dive deeper and explore one of the most fundamental navigators – the Stack Navigator.

In my early days of coding, I used to imagine the Stack Navigator as a deck of cards. You place one card on top of the other (push a screen onto the stack), and you can also remove the top card to reveal the one underneath (pop a screen from the stack). This analogy helped me visualize the concept of a stack and understand how navigation works. Maybe it’ll help you too!

Creating a Stack Navigator

Creating a Stack Navigator is straightforward. Here’s a simple example:

import { createStackNavigator } from '@react-navigation/stack';

// Create a stack navigator
const Stack = createStackNavigator();

<Stack.Navigator>
  <Stack.Screen name="Home" component={HomeScreen} />
  <Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>

In this code snippet, HomeScreen and DetailsScreen are stacked on top of each other. The first screen in the stack (the bottommost card in the deck) is the initial screen that the user sees.

Navigating Between Screens

Navigating between screens in a stack navigator is done using the navigation.navigate function. We’ve seen this in action in the previous section.

<Button
  title="Go to Details"
  onPress={() => navigation.navigate('Details')}
/>

When the ‘Go to Details’ button is pressed, the app navigates to the DetailsScreen.

Going Back

Navigating back to the previous screen is like removing the top card from the deck to reveal the one underneath. React Navigation provides the navigation.goBack function for this purpose.

<Button
  title="Go back"
  onPress={() => navigation.goBack()}
/>

When the ‘Go back’ button is pressed, the app navigates back to the previous screen in the stack.

Exploring Other Navigators: Tab and Drawer Navigators

So far, we’ve seen how the Stack Navigator can help us manage and navigate between different screens in our app. But the beauty of React Navigation is that it offers even more navigators for different use cases. In this section, we’ll introduce two other popular navigators: Tab Navigator and Drawer Navigator.

Tab Navigator

Tab Navigator allows us to create a classic bottom tab navigation pattern, much like the one you see in many popular apps like Instagram or Twitter. This pattern is great when you want your users to switch between different main screens quickly.

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

const Tab = createBottomTabNavigator();

function MyTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Settings" component={SettingsScreen} />
    </Tab.Navigator>
  );
}

In this example, we have two main screens, HomeScreen and SettingsScreen, and we can switch between them using the tabs at the bottom of the screen.

Drawer Navigator

Drawer Navigator, on the other hand, provides a sidebar menu for your app. This is a common pattern in many apps when you have multiple screens and options, and you want to keep your interface uncluttered.

Here’s a simple example of setting up a Drawer Navigator:

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

const Drawer = createDrawerNavigator();

function MyDrawer() {
  return (
    <Drawer.Navigator>
      <Drawer.Screen name="Home" component={HomeScreen} />
      <Drawer.Screen name="Notifications" component={NotificationsScreen} />
    </Drawer.Navigator>
  );
}

In this example, the HomeScreen and NotificationsScreen are accessible via a drawer menu that can be opened by swiping from the left edge of the screen or by tapping the hamburger icon in the header (if provided).

Passing Parameters Between Screens

As we navigate through the many screens of our React Native app, we often need to pass data from one screen to another. For instance, you might have a product list screen, and when a user taps on a product, you’d want to pass the product’s details to the product detail screen. This is where passing parameters between screens comes in.

React Navigation makes passing parameters between screens a breeze. In this section, I’ll show you how to pass parameters from one screen to another and how to read these parameters in the destination screen.

Passing Parameters to a Route

When calling navigation.navigate, you can pass parameters to the route you are navigating to. These parameters are then available in the destination route through the route.params property. Here’s how you can pass parameters to a route:

function ProductsListScreen({ navigation }) {
  return (
    <Button
      title="Go to ProductDetails"
      onPress={() => {
        /* 1. Navigate to the ProductDetails route with params */
        navigation.navigate('ProductDetails', {
          itemId: 86,
          otherParam: 'anything you want here',
        });
      }}
    />
  );
}

In this example, we’re passing two parameters (itemId and otherParam) to the ‘ProductDetails’ route.

Reading Parameters in a Route

As we have seen in the section 3, each screen registered in the navigator receives a navigation prop and a route prop.

Once you’ve passed parameters to a route, you can access these in the destination route through the route.params property. Here’s how you can read parameters in a route:

function ProductDetailsScreen({ route }) {
  /* 2. Get the params */
  const { itemId, otherParam } = route.params;
  return (
    <Text>ItemId: {itemId}</Text>
    <Text>Other Param: {otherParam}</Text>
  );
}

In this example, we’re reading the itemId and otherParam parameters in the ‘ProductDetails’ route, and we display them on screen.

Customizing Screen Headers

As we navigate through the different screens of our app, it’s often helpful to provide users with a visual indication of their current location within the app. This is where screen headers come in. Not only do they serve as a navigational aid, but they can also enhance the overall look and feel of your app.

By default, the Stack Navigator provides a header, but its style may not align with your app’s aesthetic. Good news! React Navigation allows us to customize screen headers to match our app’s design language. In this section, we’ll learn how to do just that.

Customizing the Header Title

The simplest way to customize the header is by changing the title. You can do this by setting the title option in the options prop of the Screen component.

<Stack.Screen
  name="Home"
  component={HomeScreen}
  options={{ title: 'My Home' }}
/>

In this example, the header title for the ‘Home’ screen is set to ‘My Home’.

Customizing the Header Style

You can also customize the style of the header. The headerStyle option lets you change the background color of the header, while the headerTintColor option changes the color of the header text and back button.

<Stack.Screen
  name="Home"
  component={HomeScreen}
  options={{
    title: 'My Home',
    headerStyle: {
      backgroundColor: '#f4511e',
    },
    headerTintColor: '#fff',
  }}
/>

Here, the header for the ‘Home’ screen has a background color of ‘#f4511e’ and a text color of ‘#fff’.

Hiding the Header

There might be some scenarios where you want to hide the header. To do this, you can set the headerShown option to false.

<Stack.Screen
  name="Home"
  component={HomeScreen}
  options={{
    headerShown: false,
  }}
/>

Advanced Techniques in React Navigation

These techniques can help you build more complex and feature-rich navigation flows to enhance your app’s user experience. In this section, we’ll discuss nested navigators, conditional rendering of routes, and dynamic navigation.

Nested Navigators

React Navigation allows you to nest navigators within other navigators. This is useful when you need different types of navigation patterns in different parts of your app. For instance, you might have a tab navigator within a stack navigator. This is possible because a Navigator is also a React component!

Here’s an example of how you can set up nested navigators:

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

function HomeTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Feed" component={FeedScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
}

function App() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="Home" component={HomeTabs} /> // <-- The Tab Navigator
      <Stack.Screen name="Details" component={DetailsScreen} />
    </Stack.Navigator>
  );
}

Here, we have a tab navigator (HomeTabs) nested within a stack navigator. The HomeTabs navigator contains two screens (FeedScreen and ProfileScreen), and the stack navigator contains the HomeTabs and DetailsScreen.

Conditional Rendering of Routes

Sometimes, you might need to render different routes based on certain conditions. For instance, you might want to show a login screen to unauthenticated users and a home screen to authenticated users. You can achieve this by conditionally rendering routes.

Here’s an example:

function App() {
  const { isAuthenticated } = useAuth();

  return (
    <Stack.Navigator>
      {isAuthenticated ? (
        <Stack.Screen name="Home" component={HomeScreen} />
      ) : (
        <Stack.Screen name="Login" component={LoginScreen} />
      )}
    </Stack.Navigator>
  );
}

In this example, we’re using a hypothetical useAuth hook that returns a boolean indicating whether the user is authenticated or not. Depending on the value of isAuthenticated, we render the HomeScreen or LoginScreen.

Dynamic Navigation

In some cases, you might not know the screens a user can navigate to at compile time. In such cases, you can use dynamic navigation. This allows you to define screens in a navigator dynamically.

Here’s an example:

function App() {
  const screens = useScreensList(); // Fetch screens from an API

  return (
    <Stack.Navigator>
      {screens.map((screen) => (
        <Stack.Screen
          key={screen.id}
          name={screen.name}
          component={screen.component}
        />
      ))}
    </Stack.Navigator>
  );
}

In this example, we’re fetching a list of screens from a hypothetical API using the useScreensList hook. We then map over the screens array to create a Screen for each item.

Wrapping up

That’s it! We’ve come a long way! From setting up React Navigation in our projects to navigating between screens, passing parameters, and even customizing headers, we’ve covered a lot of ground about getting started with React Navigation.

I encourage you to take what you’ve learned in this article and apply it to your own projects. Start small, perhaps by adding a new screen to your app, and then gradually experiment with more advanced features like nested navigators and dynamic navigation.

I hope this guide has given you the confidence to start building your own navigation flows in your apps.

If you ever find yourself stuck, don’t forget to check the React Navigation documentation. It’s an excellent resource that’s very well written and always there to help you.

Looking forward to seeing you in the next post! For more React Native resources, tips, and tutorials, be sure to stay tuned to React Native Central.

To further your understanding of React Native, have a look at some of our other articles:

Scroll to Top