loading...
Cover image for Navigation in React Native: From Zero.

Navigation in React Native: From Zero.

evangunawan profile image Evan Gunawan ・8 min read

You are developing a React Native application, and of course, you must be wanted to make your app with a lot of routes or screens. Of course, when you Googled it, you will find React Navigation. So how do we use and implement it into our application? Here, let's go and try this feature! 🤓


Before We Start

Please note, that I am using Expo for this article, please tell me if you have any problems.

Setup

If you are using expo-cli, you can run

expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context

and if you are using bare project, you can use yarn/npm to install the dependencies

yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context

For bare project, you can see the full instruction here

The navigators

First, we must know that there are some types of navigation:

  • Switch Navigator
  • Stack Navigator
  • Tab Navigators (and drawer navigators)

And, what are their differences?

1. Switch Navigator

Switch navigator allows user to switch between screens or route. It will not save your back stack, or navigation history. In real world example, if you have an app with a login screen and a dashboard screen, of course you don't want the user navigates back to login screen from dashboard using back button. The solution is switch navigator, with it, the user can not back into the login screen, instead it will exit the app from the dashboard.
As the name 'switch', the user switches between routes/screen.

Switch Navigator

See that it closes the app instead back into the home page when I pressed back

2. Stack Navigator

Stack navigator is different from switch navigator, but the function is similar, it is allows the user to navigate between screens/routes. The main difference is It will save your back stack/navigation history. You can also add a header to the screen. A header itself, is indeed the top bar of the screen. For example, you have a product list and the detail screen. In this context, you have to implement stack navigator to the screens.

Stack Navigator

3. Tabs and Drawer Navigators

It is as its name, the tabs and drawer navigators. It saves your back stack, and it will navigate the user with a press on the items. There is some variants that provided by react navigation, such as: BottomTabNavigator, MaterialTopTabNavigator, and others.
Please note that in this article, I will use BottomTabNavigator

Bottom Tab Navigator

🧭Let's Create Our Navigation!

Creating the Navigator

React Navigation let you create and customize your navigation, it can be flexible and complex. But first, lets create a simple one!

So, lets say that I have 3 Screens: Splash, Auth, and Application screen. The question is, what are we gonna use? Switch or Stack?
From the context, we have splash and authentication screen. And of course, we don't want to go back to splash screen when we are at the Authentication Screen.
So the answer is indeed Switch Navigator.

From the docs, to create a simple switch navigator, we can use this method:

createSwitchNavigator(RouteConfigs, SwitchNavigatorConfig);

and lets implement that method. Create a new file MainNavigator.js for the navigator. I usually put it inside ./navigators/ directory.

//**Other Imports**
import { createSwitchNavigator } from 'react-navigation';
export default const MainNavigator = createSwitchNavigator(
  {
    Splash: { screen: SplashScreen },
    Auth: { screen: AuthScreen },
    Application: { screen: AppScreen },
  },
  {
    initialRouteName: 'Splash',
  }
);

On the code above, we create a switch navigator with an object filled with all the 3 screens. In the object, the JSON key is the name of the route (e.g. Splash, Auth, Profile, etc.), it can be anything as it make sense. And the value is the Screen React Component itself (you should import it first).

The second parameter is SwitchNavigatorConfig, and we filled it with an object.
From the code above, the value in the object is initialRouteName, it will configure where should the navigator navigate first when it is fired. In that code, we set it to Splash, so when the MainNavigator fired/mounted, it will open SplashScreen.

There are some config that you can change and modify, like the navigation options, and many more. You can see the list in the navigator docs.

Note: Actually you can simply type Splash: SplashScreen in the navigator object, but it will be better to use the above example so that we can insert the navigationOptions later.

Mounting the Navigator into Root Component

So, we have the navigator file, and we created the navigator. How do we fire it or mount it into the application? Of course it won't be fired itself with magic, we will import, and use it inside our App.js (the root component).

const RoutedApp = createAppContainer(MainNavigator);
//**Other Imports**

export default class App extends React.Component {
  render() {
    return (
      <RoutedApp />
    );
  }
}

Then, try to launch your application. If you are using expo like me, just fire expo start. Hopefully, when you launch the application, it will navigate to SplashScreen.
Please note, that if you have some context or provider, you can wrap <RoutedApp /> with the providers. For example:

  render() {
    return (
      <ApplicationProvider>
        <FooContext.Provider value={this.state}>
          <RoutedApp />
        </FooContext.Provider>
      </ApplicationProvider>
    );
  }

It's done! you created your switch navigator.


🔍Getting Deeper

So, how to create the others? Stack Navigator and TabNavigator? It is the same, lets see from the docs, and what method did they use.

createStackNavigator(RouteConfigs, StackNavigatorConfig);
//And
createBottomTabNavigator(RouteConfigs, TabNavigatorConfig);

The difference between them all is the config of the navigator, there are complete list if you explore the navigator docs.

RouteConfigs

All 3 Navigators that I mentioned above (Switch, stack, tabs/drawer) have RouteConfigs which holds your routes/screen in one JSON object.
Here is a simple example (taken from the docs):

//**Other Imports**
import { createStackNavigator } from 'react-navigation-stack';

const foo = {
  Profile: {
    screen: ProfileScreen,
    // Optional: When deep linking or using react-navigation in a web app, this path is used:
    path: 'profile/:id',
    // The action and route params are extracted from the path.
    navigationOptions: {
      title: 'My Profile', //The header title (Topbar/actionbar title)
      ...OtherOptions
    }
  },
  ...OtherRoutes //Other routes goes here
}

export default const MyStackNavigator = createStackNavigator(foo);

navigationOptions

Switch and Stack navigator have similar navigationOptions, you can see the list here, while in tab navigator they have different options, you can check here.

And please note, that they have defaultNavigationOptions too that is written inside the NavigatorConfig (the second parameter).

//**Other Imports**
import { createStackNavigator } from 'react-navigation-stack';

const Foo = createStackNavigator(
  {
    Home: {
      screen: HomeScreen,
      navigationOptions: {
        header: null, //No header in this screen
      },
    },
    Profile: {
      screen: ProfileScreen,
      navigationOptions: {
        title: 'Test Page',
      },
    },
  },
  {
    defaultNavigationOptions: {
      headerStyle: {
        backgroundColor: 'red',
      },
    },
  });

📲Creating Full Navigation

After you learn the basics, lets move on to the complex one.

The problem

Lets have some problem!
You have an application, and you need some screen/route like this:

  • A Loading/Splash Screen
  • Authentication Screens (includes Sign In and Registration Screen)
  • The Application Screens (Home screen, Profile screen, and Edit profile screen) The user wants it to be a bottom tabbed application.

In Authentication screen, you can navigate between Sign in and registration screen. In Application Screens, we need a Bottom Tab Navigator to separate the routes inside it.
You can think and have the structure in mind before moving to the solution.

The solution

So, here we go. Lets distinguish them into 3 groups of screens, the first one is the Splash screen (it is a single screen), the Authentication group, and the Application group. For those groups, we use Switch Navigator. Easy.

Onto the next one!
Splash Screen is a single screen, so let it be.
The authentication group has 2 screens: Sign In and Registration. So let's create a Stack Navigator, call it authentication stack.
And the last one, Application group. We have 3 screens: Home, Profile, and Edit Profile. The user wants to have a bottom tab in their app. So, lets put home and profile screen into bottom tab navigator.
And, we have Edit Profile screen, which will not be on the bottom tab, of course. We will put it alongside the bottom tab navigator (home & profile), and put them into Application Stack (we will use stack navigator for the application group)

Here is the summary:

nav
The blue box is the navigator component, while the green box is your screen component.

And the code, will be somewhat like this:

//**imports here...
const AuthStack = createStackNavigator({
  Login: LoginScreen,
  Register: RegistrationScreen,
});

const TabStack = createBottomTabNavigator({
    Home: HomeScreen,
    Profile: ProfileScreen,
  }
);

const AppStack = createStackNavigator({
    MainTabs: TabStack,
    EditProfile: EditProfileScreen,
  }
);

const MainNavigator = createSwitchNavigator(
  {
    Loading: LoadingScreen,
    App: AppStack,
    Auth: AuthStack,
  },
  {
    initialRouteName: 'Loading',
  }
);
export default MainNavigator;

From the code, you can see that you can group some screens into one navigator, and put the navigator itself onto a parent navigator.

The complete code with navigation options will be posted in Github gist. (link down below)


✨Customizing Our Navigators

Creating Tab Bar Icons and Labels

The default tab bar icon do not have any icons. You should import it from outside libraries. You can just import and use @expo/vector-icons if you are using Expo. You can use other libraries too, like eva icons from @ui-kitten.

The icon and label itself is a react component, so you can create and customize those easily. Lets customize our tab bar (using expo vector icons)!

import { Ionicons } from '@expo/vector-icons';
import { createBottomTabNavigator } from 'react-navigation-tabs';
//**other imports**
const TabStack = createBottomTabNavigator(
  {
    Favorites: {
      screen: FavoritesScreen,
      navigationOptions: {
        /*
          There are 3 parameters passed that you can use,
          focused : boolean => wether the screen is focused/not
          horizontal : boolean => wether phone orientation is landscape/potrait
          tintColor : string
        */
        tabBarIcon: ({ focused, horizontal, tintColor }) => {
          let iconName = `md-heart${focused ? '' : '-empty'}`;
          return <Ionicons name={iconName} size={24} color={tintColor} />;
        },
      },
    },
    ...OtherScreens
  },
  {
    tabBarOptions: {
      showIcon: true,
      showLabel: false,
      activeTintColor: Colors.primary, //You can use hex code too.
      inactiveTintColor: Colors.primary,
    },
  }
//**Other navigators**

From the code above, you can see, the icon component is saved under tabBarIcon key in navigationOptions of FavoritesScreen. It will changes the icon when the screen is active or not.
The tabBarOptions is the default options for all icons in tab bar, you can change the tint color there. You can see the docs for the full feature list.

Screen Headers

Screen header is the top bar of your app, it can contain back button, the title, and much more.
For example, I can have a stack navigator screen with header or not with header in it. To do this, we are using navigation options of the route, the header options.

const AuthStack = createStackNavigator({
  Login: {
    screen: LoginScreen,
    navigationOptions: {
      //The screen will not have any headers.
      //Actually, you can create your own header component and insert it here!
      header: null, 
    },
  },
  Register: {
    screen: RegistrationScreen,
    navigationOptions: {
      title: 'Register', //the screen will have a header with Register title.
      headerStyle: { } //Add some style here! e.g. margin or colors
    },
  },
});

Please note that if you leave the header as default, not null, it will have back button as default. So do not worry about the top left back button


🎉And, We're Done!

At this point, you can create and customize your own routes for the navigation. Further more, you can use path in your route for more advanced feature. Also try to create a custom header or tab bar. Finally, you can learn to add some animations and create a complex custom routes.

That's was it from me. Thank you for you to read this long article 😊. I hope you can learn something from this. And please give me more feedback and suggestion if there is any mistake in the article, I would be glad to fix it.
All content in this article is completely taken from my experience in learning React Native.

And lastly, feel free to buy me a coffee☕😉.

Click me to view my full navigator code (Github gist).

Posted on by:

evangunawan profile

Evan Gunawan

@evangunawan

A university student who loves to share. Obsessed to use and learn JS Frameworks 👀

Discussion

markdown guide