React Navigation V5 news and examples

Hyo
dooboolab
Published in
6 min readDec 8, 2019

In this post followed by react-navigation v5 migration, we will look deeper in types of react-navigation in v5 and their examples.

Currently, `next` stands for v5.

In react-navigation v2 and above, we had SwitchNavigator which was pretty useful. This is deprecated in v5 and you can see the reason for their decision.

Authentication flow without SwitchNavigator in React Navigation V5

In v5 there is another api called createNativeStackNavigator and it creates what’s called NativeStackNavigator. I’ve found through testing this feature and found out that createNativeStackNavigator and createStackNavigator don’t work together at the moment. Currently, you choose one of them in order to use the stack navigation. Firstly, I’ve felt NativeStackNavigator is SwitchNavigator but I’ve found out that I was wrong reading the post.

If you read the post I’ve refered to, createNativeStackNavigator works like createStackNavigator but it is much closer to native.

Image from react-navigation official blog

See how smooth the navigation header is changing? Previously, react-navigation haven’t been developed directly connected to native. The reason is, since react-native most works on the javascript side, this approach lets the developers to quickly provide new features to users. This helps the user to customize their navigation and it worked in most cases with its flexibleness. This also lets the developer develop complex UI/UX quickly that is required in their business logic.

Today, react-navigation has reached pretty much stability. Now they are working to provide a better experience in native side so they’ve created NativeStackNavigator. Speaking like this, it may sound like NativeStackNavigator is better and unconditional to use this, but it’s not.
It’s still because native navigation is very limited because of the unexposed parts of the native api. Given its flexibility and extensibility, javascript navigation is still a good choice. Therefore, you should choose navigations optionally on the purpose of what you’re trying to achieve.

Let’s use react-navigation v5 for now.

StackNavigator & NativeStackNavigator

Above is a StackNavigator. It contains screens inside. I’ve not experienced big differences between NativeStackNavigator and StackNavigator but I’d love to compare them in-depth in the future.

  • StackNavigator is navigation that works like a stack in data structure.
import React from 'react';
import Screen1 from '../screen/Screen1';
import Screen2 from '../screen/Screen2';
import Screen3 from '../screen/Screen3';
import Screen4 from '../screen/Screen4';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useThemeContext } from '../../providers/ThemeProvider';
const Stack = createNativeStackNavigator();function RootNavigator(): React.ReactElement {
const { theme } = useThemeContext();
return (
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: theme.background,
},
headerTitleStyle: { color: theme.fontColor },
headerTintColor: theme.tintColor,
}}
>
<Stack.Screen name="Screen1" component={Screen1} />
<Stack.Screen name="Screen2" component={Screen2} />
<Stack.Screen name="Screen3" component={Screen3} />
<Stack.Screen name="Screen4" component={Screen4} />
</Stack.Navigator>
);
}
export default RootNavigator;

DrawerNavigator

Origin comes from Android. When you press the button as shown below, you can open and close the menu slider next to it. You can also change the screen on the right side of the menu on the left.

Original it comes from Android. When you press the button as shown below, you can open and close the menu slider next to it. You can also change the screen on the right side.

import { DrawerItem, createDrawerNavigator } from '@react-navigation/drawer';
import React, { ReactElement } from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import DrawerScreen1 from '../screen/DrawerScreen1';
import DrawerScreen2 from '../screen/DrawerScreen2';
import { useSafeArea } from 'react-native-safe-area-context';
const Drawer = createDrawerNavigator();const styles = StyleSheet.create({
container: {
flex: 1,
},
});
function CustomDrawerContent({ drawerPosition, navigation }): ReactElement {
const insets = useSafeArea();
return (
<ScrollView
contentContainerStyle={[
{
paddingTop: insets.top + 4,
paddingLeft: drawerPosition === 'left'
? insets.left : 0,
paddingRight: drawerPosition === 'right'
? insets.right : 0,
},
]}
style={styles.container}
>
<DrawerItem
label="Screen1"
onPress={(): void => {
navigation.navigate('DrawerScreen1');
}}
/>
<DrawerItem
label="Screen2"
onPress={(): void => {
navigation.navigate('DrawerScreen2');
}}
/>
<DrawerItem
label="Close"
onPress={(): void => {
navigation.closeDrawer();
}}
/>
</ScrollView>
);
}
function Navigator(): ReactElement {
return (
<Drawer.Navigator
drawerContent={(props): ReactElement => (
<CustomDrawerContent {...props} />
)}
>
<Drawer.Screen
name="DrawerScreen1"
component={DrawerScreen1} />
<Drawer.Screen
name="DrawerScreen2"
component={DrawerScreen2} />
</Drawer.Navigator>
);
}
export default Navigator;

BottomTabNavigator

This navigation is mainly used in iOS. There are buttons below, and each press of the button switches the screens.

import React, { ReactElement } from 'react';import { IC_MASK } from '../../utils/Icons';
import { Image } from 'react-native';
import Screen1 from '../screen/Screen1';
import Screen2 from '../screen/Screen2';
import Screen3 from '../screen/Screen3';
import Screen4 from '../screen/Screen4';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();const TabBarIcon = (focused: boolean): ReactElement => {
return (
<Image
style={{
width: focused ? 24 : 18,
height: focused ? 24 : 18,
}}
source={IC_MASK}
/>
);
};
function Navigator(): ReactElement {
return (
<Tab.Navigator
screenOptions={{
tabBarIcon: ({ focused }): ReactElement =>
TabBarIcon(focused),
}}
>
<Tab.Screen
name="Screen1"
component={Screen1}
options={{
tabBarLabel: 'Screen1',
tabBarIcon: ({ focused }): ReactElement =>
TabBarIcon(focused),
}}
/>
<Tab.Screen name="Screen2" component={Screen2} />
<Tab.Screen name="Screen3" component={Screen3} />
<Tab.Screen name="Screen4" component={Screen4} />
</Tab.Navigator>
);
}
export default Navigator;

MaterialTopTabNavigator

This is the navigation that follows Android’s material guidelines. By default, you can slide the screen from side to side, and the indicator slides along with it.

import React, { ReactElement } from 'react';import Screen1 from '../screen/Screen1';
import Screen2 from '../screen/Screen2';
import Screen3 from '../screen/Screen3';
import Screen4 from '../screen/Screen4';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
const Tab = createMaterialTopTabNavigator();function Navigator(): ReactElement {
return (
<Tab.Navigator
tabBarOptions={{
labelStyle: { fontSize: 12 },
style: { backgroundColor: 'blue' },
}}
>
<Tab.Screen name="Screen1" component={Screen1} />
<Tab.Screen name="Screen2" component={Screen2} />
<Tab.Screen name="Screen3" component={Screen3} />
<Tab.Screen
name="Screen4"
component={Screen4}
options={{ tabBarLabel: 'Custom4' }}
/>
</Tab.Navigator>
);
}
export default Navigator;tabBarOptions is used to give defaultNavigationOption. If you want to give navigationOption individually, you can add property value in option parameter
  • tabBarOptions is used to give defaultNavigationOption. If you want to give navigationOption individually, you can add property value in options the parameter.

MaterialBottomTabNavigator

This time, the navigation is located below according to the Android Material Design Guide. Basically, the slight difference is that when the screen is activated, it grows as the contents inside the button are animated. In addition, if the button is inactive, text is not showing. Basically, it is as follows but of course, you can customize it.

import React, { ReactElement } from 'react';import { IC_MASK } from '../../utils/Icons';
import { Image } from 'react-native';
import Screen1 from '../screen/Screen1';
import Screen2 from '../screen/Screen2';
import Screen3 from '../screen/Screen3';
import Screen4 from '../screen/Screen4';
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
const Tab = createMaterialBottomTabNavigator();const TabBarIcon = (focused: boolean): ReactElement => {
return (
<Image
style={{
width: focused ? 24 : 18,
height: focused ? 24 : 18,
}}
source={IC_MASK}
/>
);
};
function Navigator(): ReactElement {
return (
<Tab.Navigator
screenOptions={{
tabBarIcon: ({ focused }): ReactElement =>
TabBarIcon(focused),
}}
>
<Tab.Screen
name="Screen1"
component={Screen1}
options={{
tabBarLabel: 'Screen1',
tabBarIcon: ({ focused }): ReactElement =>
TabBarIcon(focused),
}}
/>
<Tab.Screen name="Screen2" component={Screen2} />
<Tab.Screen name="Screen3" component={Screen3} />
<Tab.Screen name="Screen4" component={Screen4} />
</Tab.Navigator>
);
}
export default Navigator;

Conclusion

React navigation v5 has changed a lot in design, but the existing navigations keep things well in the past. The lack of SwitchNavigator remains unfortunate but NativeStackNavigation which can better digest native is expected in future development. I’ve not felt a tremendous benefit so far using NativeStackNavigation but as I code, I expect to see some differences.

The above example is in React Navigation V5 example repository so please feel free to clone it and test it 😄.

We hope you will also be interested in the opensource HackaTalk which is the leading introduction and use of React Navigation V5.

--

--