Comprehensive routing and navigation in React Native made easy
For both iOS and Android
Having worked with Xamarin Forms on my current project for the last 14 months, I am considering using React Native for my next project. First, I have to convince myself that for everything I have done in Xamarin Forms, I should be able to do the exact same thing in React Native as easily or more easily. One thing that’s super easy to do in Xamarin Forms is navigation which is better known in React Native as “routing and/or navigation”. From my findings, in React Native, that’s no so easy. There are tons of ways to do routing, but none of them is really comprehensive.
From here on until the end of the article, I will never mention Xamarin Forms again, because this post is about React Native.
So in React Native, what’s the difference between routing and navigation? It helps me to think of routing as the mechanism to present different pages on the mobile device and navigation as the mechanism that shows the correct title, left element and right element on the toolbar. Typically, the left element can be either either a left arrow icon which allows users to navigate back to the previous page or a close icon which closes the current page (which also exposes the previous page again). This distinction will be clearer in a minute. The title on the toolbar of course has to reflect the name of the page.
To illustrate, consider the app we want to build as having tabs (aka bottom bar navigation in Android) and also a slide drawer menu. As users click on each tab element, a different page is presented. The title in the toolbar reflects the correct page that’s being displayed. Figure 1 shows this interaction.
Next, when users clicks on the “hamburger menu”, a slide drawer menu slides out as shown in Figure 2. The left element now shows the back arrow instead of the hamburger menu. If users clicks on the bak arrow, the slide menu slides back in.
Now, instead of clicking on the back arrow, let’s say users click on the “Client” menu item in the drawer menu, a new page gets pushed on top of the stack. This page covers the tabs (bottom bar navigation) and also prevents the slide drawer menu to show again. Basically, at this point, users can only dismiss this page by clicking on the Close icon in the top left of the page. Again the title in the toolbar says Client” which correctly reflects the page we’re looking at. This is shown in Figure 3.
Notice one more thing. On Android, the color scheme of the status bar and toolbar follows the Material Design guide lines. On iOS, this does not have to be the case.
Just in case any one of us forgets, the objective is to build the above app that handles all the routing and navigation illustrated above. Again routing switches the pages and navigation ensures the title in the toolbar correctly reflects the page being shown. This should cover the majority of the routing use cases. The remaining routing use cases could be something like showing bottom sheet pages, modal dialogs, context menu, etc.
So let’s start.
Fortunately, we don’t have to start from scratch. There are already a couple of packages in the React Native ecosystem to help us out. But on the other hand, we don’t want to import too many packages just to handle this routing and navigation task. So 2 is a good number and these 2 packages to help us are:
So let’s say our app is called easyRNRoute where the entry point to the app is:
AppRegistry.registerComponent(‘easyRNRoute’, () => easyRNRoute);
We want the root component of the app is the DrawerNavigator. In other words, DrawerNavigator is the outermost navigator. Nested inside DrawerNavigator are the main App and the StackNavigator. Let’s show the code first.
const stackNavigator = StackNavigator({
Info: { screen: InfoView },
Settings: {screen: SettingsView },
Bookmark: {screen: BookmarkView },
Calendar: {screen: CalendarView},
Client: {screen: ClientView},
}, {
headerMode: 'none'
});const easyRNRoute = DrawerNavigator({
Home: {
screen: App,
},
Stack: {
screen: stackNavigator
}
}, {
contentComponent: DrawerMenu,
contentOptions: {
activeTintColor: ‘#e91e63’,
style: {
flex: 1,
paddingTop: 15,
}
}
});
Let’s talk about the StackNavigator first. Refer to Figure 2 above, when the “Client” menu item is selected, the StackNavigator places the “Client” page on top of the page stack (as shown in Figure 3). “Bookmark, “Info”, “Settings”, “Calendar” follow the same pattern but are not shown. Anyway, the job of the StackNavigator is to ensure when any one of those is selected, its corresponding page is placed at the top of the stack of pages.
Moving on, the main App contains the BottomNavigation component and also a component (TabContentNavigator) that we will write to handle when each tab element is selected. Here’s the entire code for the App component:
In the render() function above, there’s a BottomNavigation component with 4 elements in it, corresponding to Today, Profile, Map and Chat. This was shown previously in the screenshot and they correspond should be obvious.
Then there are Container, Toolbar, StatusBar and again they should all be obvious. The only component that pertains to the topic at hand here is the TabContentNavigator.
The TabContentNavigator is what we have to write. But we don’t have to write from scratch because we can use TabRouter.
Now probably wonder why TabRouter instead of TabNavigator? The reason is because TabNavigator actually includes the tab bar, but in our app we already have the tab coming from the package https://github.com/xotahal/react-native-material-ui, so all we need is the routing feature.
Here’s the code for TabContentNavigator:
Points of interest
1- To route to a certain page, use React Navigation API navigate(). This function navigate() is a method of the navigation property of the props. For example, to open and close the drawer menu, do something like
this.props.navigation.navigate('DrawerOpen');
this.props.navigation.navigate('DrawerClose');
To route to the Calendar page, do
this.props.navigation.navigate(‘Calendar’);
and so on.
2- The View component that gets rendered for each tab element do not contain the Status bar and toolbar. Other pages such as the one we have seen Client do (Figure 3). In the sample code, I distinct these 2 types in 2 different folder “Content” and “Pages”. This grouping is just arbitrary.
3- To get the StatusBar and Toolbar to render according to the Material Design guidelines on Android and also on iOS, we just have to play with the style.
In summary, what I present here can be easily used as a skeleton for your next React Native app. Checkout the screenshot. If your app requires a similar UI pattern, then you should be already good to go. Otherwise, some minor tweaks might be required.