How to add a Drawer Inside Stack Navigation in React Navigation
For those looking for the solution in react-navigation
5.X, you can do it like this:
Drawer Navigator
const ProductListWithDrawer = () => {
return (
<Drawer.Navigator initialRouteName="ProductList">
<Drawer.Screen name="ProductList" component={screens.ProductList} />
<Drawer.Screen name="ProductDetail" component={screens.ProductDetailScreen} />
</Drawer.Navigator>
);
};
Stack Navigator (should be wrapped inside a Navigation Container)
<Stack.Navigator initialRouteName="Dashboard" screenOptions={{ headerShown: false }}>
<Stack.Screen name="Dashboard" component={screens.Dashboard} />
<Stack.Screen name="Loading" component={screens.Loading} />
<Stack.Screen name="Chat" component={screens.Chat} />
<Stack.Screen name="ProductListWithDrawer" component={ProductListWithDrawer} /> //our drawer
</Stack.Navigator>
Basically, this should get the work done. One more thing that could be the issue here is while navigating to those screens inside drawer navigator with params. In that case, it can be done like this:
navigation.navigate("ProductListWithDrawer", {
screen: "ProductList",
params: { user: "Alex"},
});
This has also been explained in Nesting navigators.
I have just created an example that probably cases you need.
import React, {Component} from 'react';
import {
StyleSheet,
Button,
Image,
TouchableWithoutFeedback,
View,
} from 'react-native';
import {
createDrawerNavigator,
createStackNavigator,
StackActions,
NavigationActions,
} from 'react-navigation';
class HomeScreen extends React.Component {
render() {
return (
<View style={styles.container}>
<Button
onPress={() => this.props.navigation.navigate('Notifications')}
title="Go to notifications"
/>
</View>
);
}
}
class NotificationsScreen extends React.Component {
render() {
return (
<View style={styles.container}>
<Button
onPress={() => this.props.navigation.navigate('Home')}
title="Go back home"
/>
</View>
);
}
}
class LoginScreen extends Component {
openDashboard = () => {
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({routeName: 'Dashboard'})],
});
this.props.navigation.dispatch(resetAction);
}
render() {
return (
<View style={styles.container}>
<Button
onPress={this.openDashboard}
title={'Login'}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 20,
},
icon: {
width: 24,
height: 24,
},
menu: {
marginRight: 8,
}
});
const renderMenu = (navigation) => (
<TouchableWithoutFeedback onPress={() => navigation.openDrawer()}>
<Image
source={require('./menu.png')}
style={[styles.icon, styles.menu]}
/>
</TouchableWithoutFeedback>
)
const Home = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({navigation}) => ({
title: 'Home',
headerRight: renderMenu(navigation)
}),
}
})
const Notifications = createStackNavigator({
Notifications: {
screen: NotificationsScreen,
navigationOptions: ({navigation}) => ({
title: 'Notifications',
headerRight: renderMenu(navigation)
})
}
})
const Dashboard = createDrawerNavigator(
{
Home: {
screen: Home,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: (
<Image
source={require('./chats-icon.png')}
style={styles.icon}
/>
),
}
},
Notifications: {
screen: Notifications,
navigationOptions: {
drawerLabel: 'Notifications',
drawerIcon: (
<Image
source={require('./notif-icon.png')}
style={styles.icon}
/>
),
}
},
},
{
drawerPosition: 'right'
}
);
const App = createStackNavigator(
{
Login: LoginScreen,
Dashboard: Dashboard
},
{
initialRouteName: 'Login',
headerMode: 'none'
}
)
export default App;
- When user presses login button on LoginScreen the navigation will be reseted (so that the user can't goes back to the login screen via the back arrow or the physical back button on android).
- Then we create a Drawer to the right with two screens and with a hamburger icon.
- The sub screens for the Home should be inside the Home stack and the same for the notifications.
You just need to add the missing icons.
Showing drawer from right side.
Add a drawer Position
parameter when create Drawer Navigator.
const DrawerNav = createDrawerNavigator({
DashboardStack: Dashboard,
},
{
drawerPosition: 'right'
});
Call DrawerNavigation from header's button.
Add a button to the header for toggleDrawer
in Dashboard.js
. You can get the navigation instance as below in navigationOptions
;
class Dashboard extends React.Component {
static navigationOptions = ({navigation, navigationOptions}) => {
return {
headerTitle: 'Dashboard@@',
headerLeft: <Text>Left</Text>,
headerRight: (
<Button onPress = {navigation.toggleDrawer}
title="Menu"
color="#fff">
<Text>Menu</Text>
</Button>
),
headerTitleStyle: {
flex: 1,
color: '#fff',
textAlign: 'center',
alignSelf: 'center',
fontWeight: 'normal',
},
headerStyle: {
backgroundColor: '#b5259e',
},
}
}
You could change button to Touchable Opacity or another one.
Wrap AuthStackNavigation
and DrawerNavigation
using another Navigator.
Wrap your navigation using createSwitchNavigation
or another and export.
// App.js
import React from 'react';
import {
createStackNavigator,
createDrawerNavigator,
createSwitchNavigator,
} from 'react-navigation';
import HomeScreen from './srcs/screens/Home';
import Dashboard from './srcs/screens/Dashboard';
const AuthStackNavigation = createStackNavigator({
HomeStack: HomeScreen,
LoginStack: HomeScreen,
RegisterStack: HomeScreen,
}, {
initialRouteName: 'HomeStack',
})
const DashboardStack = createStackNavigator({ // For header options
Dashboard: Dashboard
})
const DrawerNav = createDrawerNavigator({
DashboardStack: DashboardStack,
SecondScreen: Dashboard, // You should use another screen.
ThirdScreen: Dashboard,
})
const MainNavigation = createSwitchNavigator({
HomeDrawer: DrawerNav,
AuthStack: AuthStackNavigation, // You will use this.props.navigation.replace('HomeDrawer') after login process.
})
export default MainNavigation // Stack, Drawer, Switch naviagtions return react component.