In this post followed by react-navigation v5 migration, we will look deeper in types of react-navigation in v5 and their examples.
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.
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.
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 givedefaultNavigationOption
. If you want to givenavigationOption
individually, you can add property value inoptions
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.