Multiple Navigators React Native
In complex applications, handling navigation becomes a daunting task. We end up having stack navigators, drawer navigators and tab navigators, and we must handle them all well in order to produce a smooth and simple user interface. In this article, we will take a look at how we can have multiple navigators in React Native, i.e. the stack, drawer and tab navigators.
Step one is creating the app and the screens. You can either create your own screens, use existing screens, or use the code given below to make your screens. All screens would be stored in a directory src/screens. I have also skipped import statements and styles for brevity.
Home.js
export default class Home extends Component {render() {
return(
<View style={styles.container}>
<TouchableOpacity onPress={() => this.props.navigation.openDrawer()} style={styles.btn}>
<Text>Open Drawer</Text>
</TouchableOpacity>
<Text style={styles.infoText}>Home Screen</Text>
<TouchableOpacity style={styles.btn} onPress={() => this.props.navigation.navigate('StackScreen')}>
<Text>Stack Navigation</Text>
</TouchableOpacity>
</View>
);
}
}
StackScreen.js
export default class StackScreen extends Component {render() {
return(
<View style={styles.container}>
<Text style={styles.infoText}>Stack Screen</Text>
</View>
);
}
}
TabA.js
export default class TabA extends Component {
render() {
return(
<View style={styles.container}>
<TouchableOpacity onPress={() => this.props.navigation.openDrawer()} style={styles.btn}>
<Text>Open Drawer</Text>
</TouchableOpacity>
<Text style={styles.infoText}>Tab-A</Text>
</View>
);
}
}
In these screens, you will notice the following:
this.props.navigation.openDrawer()
this means that the Home screen as well as the TabA screen would have a drawer. In my case, I have left the drawer on the left (default), but you could choose to have it in whichever position you wish. I have not given a drawer option in the stack screen, and the drawer will not be accessible from this screen.
That said, these screens now need to be put inside the navigators.
I created all my navigators in my App.js, but it is a good practice to have separate files for navigators and put these in a directory called navigation.
Before adding navigators, make sure you have installed the react-navigation package from npm. In case you haven’t, run npm install --save react-navigation
from the terminal at your project root to install this package.
The first step is to import the create functions for navigators. Make sure you have this statement along with your other import statements:
import {createStackNavigator, createDrawerNavigator, createBottomTabNavigator, createAppContainer} from ‘react-navigation’;
Next, we will create the Stack Navigator.
const StackNav = createStackNavigator(
{
Home: Home,
StackScreen: StackScreen,
},
{
initialRouteName: 'Home'
}
);
This stack navigator will later be a child of the tab navigator. Let’s write the code for the Tab Navigator now.
const TabNav = createBottomTabNavigator(
{
Home: StackNav,
TabA: TabA,
},
{
tabBarOptions: {
activeTintColor: 'red',
inactiveTintColor: 'blue',
labelStyle: {
fontSize: 18,
},
style: {
backgroundColor: 'aliceblue'
}
},
}
);
The tab navigator only contains two tabs, but you could add more if you want. I’ve also kept the active and inactive tint colors to red and blue respectively, which may not be a very good combination, but you could use whatever colors fit best with the rest of the app.
Things get slightly tricky now, since the content of the drawer must be the tabs in out tab navigator. Hence, we first write a SIdeMenu component, which will be the content of our drawer.
class SideMenu extends Component {
render() {
return(
<ScrollView>
<TouchableOpacity
style={styles.drawerItem}
onPress={() => {
this.props.navigation.navigate('Home');
this.props.navigation.closeDrawer();
}
}>
<Text style={styles.drawerText}>Home</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.drawerItem}
onPress={() => {
this.props.navigation.navigate('TabA');
this.props.navigation.closeDrawer();
}
}>
<Text style={styles.drawerText}>Tab-A</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.drawerItem}
onPress={() => {
this.props.navigation.navigate('TabB');
this.props.navigation.closeDrawer();
}
}>
<Text style={styles.drawerText}>Tab-B</Text>
</TouchableOpacity>
</ScrollView>
);
}
}
Now, we write the Drawer itself, which is pretty simple:
const DrawerNav = createDrawerNavigator(
{
Home: TabNav,
},
{
contentComponent: SideMenu
}
);
The last step is to create an App Container and use it in App.js
const AppContainer = createAppContainer(DrawerNav);export default class App extends Component {
render() {
return(
<View style={styles.container}>
<AppContainer />
</View>
);
}
}
Done, you now have a drawer and a tab for the same screens. Why you may want to do this, I don’t know, but in case you do, you can. Here is the complete code for App.js (again, I have omitted the import statements and the styles for brevity)
App.js
const StackNav = createStackNavigator(
{
Home: Home,
StackScreen: StackScreen,
},
{
initialRouteName: 'Home'
}
);const TabNav = createBottomTabNavigator(
{
Home: StackNav,
TabA: TabA,
TabB: TabB
},
{
tabBarOptions: {
activeTintColor: 'red',
inactiveTintColor: 'blue',
labelStyle: {
fontSize: 18,
},
style: {
backgroundColor: 'aliceblue'
}
},
}
);class SideMenu extends Component {
render() {
return(
<ScrollView>
<TouchableOpacity
style={styles.drawerItem}
onPress={() => {
this.props.navigation.navigate('Home');
this.props.navigation.closeDrawer();
}
}>
<Text style={styles.drawerText}>Home</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.drawerItem}
onPress={() => {
this.props.navigation.navigate('TabA');
this.props.navigation.closeDrawer();
}
}>
<Text style={styles.drawerText}>Tab-A</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.drawerItem}
onPress={() => {
this.props.navigation.navigate('TabB');
this.props.navigation.closeDrawer();
}
}>
<Text style={styles.drawerText}>Tab-B</Text>
</TouchableOpacity>
</ScrollView>
);
}
}const DrawerNav = createDrawerNavigator(
{
Home: TabNav,
},
{
contentComponent: SideMenu
}
);const AppContainer = createAppContainer(DrawerNav);export default class App extends Component {
render() {
return(
<View style={styles.container}>
<AppContainer />
</View>
);
}
}
Once again, it is a good idea to have different navigators in different files and place them inside a navigation/ directory. Hope this article helped!