Implementing Sidebar Navigation in React Native
In many mobile application, you will see the Hamburger icon so when you click on that icon a sidebar open and display the information about a logged in user, profile photo at top and application screen links to move on further screens , you can see the demo of video of this just in Post Video section in side panel, and as per your project need you place the screen links there in sidebar react native.
I will expain you , how you can create a sidebar menu with react native application and open when user click on it. we will create a class Routes and will add screen Login,Signup,Dashboard,ForgotPassword to it. The flow will be user logged in to mobile application and redirected to dashboard screen. Here we will check weather user logged in or not in dashboard screen not in routes class. For session storage in mobile application the package @react-native-async-storage/async-storage Required.
Post Video: Sidebar React native
import React, { Component } from 'react'; import { Router, Stack, Scene } from 'react-native-router-flux'; import Login from './containers/Login'; import Signup from './containers/Signup'; import Dashboard from './containers/Dashboard'; import ForgotPassword from './containers/ForgotPassword'; export default class Routes extends Component { constructor(props) { super(props); } render() { return ( <Router> <Stack key="root" hideNavBar={true}> <Scene key="login" component={Login} title="Login" /> <Scene key="signup" component={Signup} title="Register" /> <Scene key="forgotpassword" component={ForgotPassword} title="ForgotPassword" /> <Scene key="dashboard" component={Dashboard} title="Dashboard" /> </Stack> </Router> ) } }
Below is login class screen , it has _bootstrapAsync function , it will read the storage data and if data if valid or not found redirected to respective screen accordinlgy. Because in react native side bar menu , we display user login information & profile photo and also other details as per our needed of a project. doLogin function call api using Axios and validate the use login credentials and if successful Actions.dashboard({ 'username': response.data.profile.username, 'usertypename': response.data.profile.usertypename, 'isLoggedIn': true, 'profile_photo': response.data.profile.profile_photo }); set the Screen Props. we will access these screen props in dashboard class.
export default class Login extends Component { constructor(props) { super(props); this.state = { email: '', password: '', forgotEmail: '', versionName: 'v1.0.0', loading: false, isModalVisible: false, netStatus: 'none', dialogVisible: false, errorForgotEmail: "", isLoggedIn: false } this.FlashMessageComponent = React.createRef(); this._bootstrapAsync = this._bootstrapAsync.bind(this); } async componentDidMount() { NetInfo.fetch().then((connectionInfo) => { this.setState({ 'netStatus': connectionInfo.type }); }); //NetInfo.addEventListener('connectionChange',this.handleConnectivityChange); this._bootstrapAsync(); } _bootstrapAsync = async () => { try { const saved = await storage.getItem('user'); const isLoggedIn = await storage.getItem('isLoggedIn'); const storedItem = JSON.parse(saved); if (storedItem !== null && isLoggedIn == 1) { if (storedItem.userId > 0 && storedItem.userId != "") { this.setState({ 'isLoggedIn': true }); Actions.dashboard({ 'username': storedItem.username, 'usertypename': storedItem.usertypename, 'isLoggedIn': true }); } else { Actions.login(); } } } catch (e) { console.warn(e); } }; handleConnectivityChange = (connectionInfo) => { this.setState({ 'netStatus': connectionInfo.type }); } signup = () => { if (!this.state.loading) { Actions.signup(); } } forgotpassword = () => { if (!this.state.loading) { Actions.forgotpassword(); } } emailChange = (text) => { this.setState({ email: text }); } passwordChange = (text) => { this.setState({ password: text }); } forgotEmailChange = (text) => { this.setState({ forgotEmail: text }); } _toggleModal = () => { if (!this.state.loading) { this.setState({ isModalVisible: !this.state.isModalVisible }); } } _toggleModalOkClick = () => { } doLogin() { const user = { email: this.state.email, password: this.state.password, }; if (!this.state.loading) { if (this.state.netStatus != "none") { this.setState({ loading: true }); axios.post(apiUrl + 'user/login', user, auth).then(response => { //var res_data = response.data; if (response.data.status == 1) { var userA = { userId: response.data.profile.userId, username: response.data.profile.username, email: response.data.profile.email, usertype: response.data.profile.usertype, usertypename: response.data.profile.usertypename, contactno: response.data.profile.contact_no, profile_photo: response.data.profile.profile_photo, }; storage.setItem('user', JSON.stringify(userA)); storage.setItem('isLoggedIn', JSON.stringify(1)); this.setState({ 'isLoggedIn': true }); this.email.setNativeProps({ text: '' }) this.password.setNativeProps({ text: '' }) this.setState({ password: '', email: '' }); Actions.dashboard({ 'username': response.data.profile.username, 'usertypename': response.data.profile.usertypename, 'isLoggedIn': true, 'profile_photo': response.data.profile.profile_photo }); } else if (response.data.status == 0) { Alert.alert( 'Tirth Purohit', response.data.msg, [ { text: 'OK', onPress: () => console.log('OK Pressed') }, ], { cancelable: true } ) this.setState({ loading: false }); } else { Alert.alert( 'Tirth Purohit', 'some error occurred, Please try after few minutes.', [ { text: 'OK', onPress: () => console.log('OK Pressed') }, ], { cancelable: true } ) this.setState({ loading: false }); } }).catch(error => { var res_data = error.response; if (!res_data.data.status) { Alert.alert( 'Tirth Purohit', error.response.data.msg, [ { text: 'OK', onPress: () => console.log('OK Pressed') }, ], { cancelable: true } ) } else { Alert.alert( 'Tirth Purohit', 'There is some issue , try later: ' + error.response.status, [ { text: 'OK', onPress: () => console.log('OK Pressed') }, ], { cancelable: true } ) } this.setState({ loading: false }); }); } else { Alert.alert( 'Tirth Purohit', netErrorMsg, [ { text: 'OK', onPress: () => console.log('OK Pressed') }, ], { cancelable: true } ) this.setState({ loading: false }); } } } render() { return ( <View style={styles.mainContainer}> <KeyboardAvoidingView style={styles.container} behavior="padding" > <View style={(styles.row, styles.imageBox, styles.logo)}> <Image style={{ width: 190, height: 32 }} source={{ uri: apiUrl + 'assets/images/signin-logo.png' }} /> </View> <View style={{ width: width - 90, alignItems: 'center', justifyContent: 'center' }}> <Text style={styles.pageTitle}>Login Here</Text> </View> <FlashMessageComponent ref={this.FlashMessageComponent} /> <TextInput style={styles.inputBox} underlineColorAndroid='rgba(0,0,0,0)' placeholder="Email" placeholderTextColor="#999999" selectionColor="#000" keyboardType="email-address" onSubmitEditing={() => this.password.focus()} onChangeText={this.emailChange} ref={(input) => { this.email = input }} /> <TextInput style={styles.inputBox} underlineColorAndroid='rgba(0,0,0,0)' placeholder="Password" secureTextEntry={true} selectionColor="#000" placeholderTextColor="#999999" ref={(input) => this.password = input} onChangeText={this.passwordChange} /> <View style={styles.scrollboxActionContainer}> <View style={styles.buttonSignup}> <TouchableOpacity onPress={ () => this.doLogin()} > <Text style={styles.buttonSignupText}>Login</Text> </TouchableOpacity> </View> </View> <View style={{ flexDirection: "row" }}> <View style={{ flex: 1, paddingLeft: 10, }}> <TouchableOpacity style={{ alignSelf: 'stretch' }} onPress={this.signup}> <Text style={styles.button_1}>Create Account?</Text> </TouchableOpacity> </View> <View style={{ borderLeftWidth: 1, borderLeftColor: 'white' }} /> <View style={{ flex: 1, paddingRight: 10 }}> <TouchableOpacity style={{ alignSelf: 'stretch' }} onPress={this.forgotpassword}> <Text style={styles.button_2}>Forgot Password?</Text> </TouchableOpacity> </View> </View> {(this.state.loading && <View style={styles.loading}> <ActivityIndicator size="large" color="#0000ff" animating={this.state.loading} /> </View> )} </KeyboardAvoidingView> <View style={styles.signupTextCont}> </View> </View> ); } }
We have to create a class dashboard ,Which will look like below and which will use createDrawerNavigator,createStackNavigator,createSwitchNavigator to create react native side bar menu. You can see in source code that createDrawerNavigator contain the screens with drawerLabel means what links with icon will be visible to your side bar menu drawer , also you can see AccountSecurity , ProfilePhoto has drawerLabel and drawerIcon as null , It means we don't want to show these screen link in side bar menu but we want to use it as navigation. initialRouteName is AppDashboard with checking weather user logged in or not.
import React from 'react'; import { Text, StyleSheet, View, Button, Image, TouchableOpacity, ActivityIndicator, TouchableHighlight, Dimensions, TextInput, Alert, ScrollView } from 'react-native'; import storage from '@react-native-async-storage/async-storage'; import styles from "../css/dashboard"; import { Ionicons } from '@expo/vector-icons'; import { Avatar } from 'react-native-paper'; import { apiUrl, netErrorMsg, axiosHeaders } from "../config/constant"; import { Actions } from 'react-native-router-flux'; import { createAppContainer, createSwitchNavigator } from 'react-navigation'; import { createStackNavigator } from 'react-navigation-stack'; import { createDrawerNavigator, DrawerItems } from 'react-navigation-drawer'; import { Container, Content, Icon, Header, Body, Form } from 'native-base'; import { SafeAreaView } from 'react-native-safe-area-context'; import HomeScreen from "./pages/HomeScreen"; import SettingsScreen from "./pages/SettingsScreen"; import ShareScreen from "./pages/ShareScreen"; import YourAccountsScreen from "./pages/YourAccountsScreen"; import LoginScreen from "./Login"; import AccountSecurityScreen from './pages/AccountSecurityScreen'; import ProfilePhotoScreen from './pages/ProfilePhotoScreen'; const CustomDrawerContentComponent = (props) => { return ( <Container> <Header style={styles.drawerHeader}> <Body> <View style={styles.drawerHeader}> <View style={styles.logo, { flex: 2, paddingTop: '5%' }}> <Image style={{ width: 190, height: 32 }} source={{ uri: apiUrl + 'assets/images/signin-logo.png' }} /> <Text style={{ alignContent: 'center', alignSelf: 'center' }}>Welcome {props.screenProps.username}</Text> <Text style={{ alignContent: 'center', alignSelf: 'center' }}> {props.screenProps.usertypename}</Text> </View> <View style={{ flex: 1, paddingTop: '5%' }}> <TouchableOpacity onPress={() => props.navigation.navigate('ProfilePhoto', { ActionPanelActiveTab: 'EPP' })} style={styles.signoutContainer}> <Image style={styles.profileImgContainer} source={{ uri: props.screenProps.profile_photo }} /> </TouchableOpacity> </View> </View> </Body> </Header> <Content style={{ marginTop: -2 }}> <ScrollView> <SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}> <DrawerItems {...props} /> <TouchableOpacity onPress={() => Alert.alert( 'Log out', 'Do you want to logout?', [ { text: 'Cancel', onPress: () => { return null } }, { text: 'Confirm', onPress: () => { storage.removeItem('user'); storage.removeItem('isLoggedIn'); Actions.login(); } }, ], { cancelable: false } ) }> <Text style={{ margin: 16, fontWeight: 'bold', color: 'red', 'paddingLeft': '15%' }}> Logout </Text> </TouchableOpacity> </SafeAreaView> </ScrollView> </Content> </Container> ) }; const MyDrawerNavigator = createDrawerNavigator({ Home: { screen: HomeScreen, navigationOptions: ({ navigation }) => { return { //drawerLabel: () => null, //drawerIcon: () => null, drawerLabel: function () { return ( <View style={styles.sidebar_hr_bottom}> <Text style={styles.navigation_text}>Home</Text> <Text style={styles.navigation_bagage_text}>Back to home...</Text> </View> ) }, drawerIcon: ({ tintColor }) => ( <Ionicons style={styles.icons} name="home-outline" size={24}></Ionicons> ), } } }, YourAccounts: { screen: YourAccountsScreen, //screen: (props) => <YourAccountsScreen {...props} ActionPanelActiveTab='EP' />, navigationOptions: ({ navigation }) => { return { //drawerLabel: () => null, drawerLabel: function () { return ( <View style={styles.sidebar_hr_bottom}> <Text style={styles.navigation_text}>Your Accounts</Text> <Text style={styles.navigation_bagage_text}>Profile , Password & others...</Text> </View> ) }, drawerIcon: ({ tintColor }) => ( <Ionicons style={styles.icons} name="person-outline" size={24}></Ionicons> ), } } }, Share: { screen: ShareScreen, navigationOptions: ({ navigation }) => { return { //drawerLabel: () => null, drawerLabel: function () { return ( <View style={styles.sidebar_hr_bottom}> <Text style={styles.navigation_text}>Share</Text> <Text style={styles.navigation_bagage_text}>Let others know about the app!</Text> </View> ) }, drawerIcon: ({ tintColor }) => ( <Ionicons style={styles.icons} name="share-social-outline" size={24}></Ionicons> ), } } }, Settings: { screen: SettingsScreen, navigationOptions: ({ navigation }) => { return { //drawerLabel: () => null, drawerLabel: function () { return ( <View style={styles.sidebar_hr_bottom}> <Text style={styles.navigation_text}>Settings</Text> <Text style={styles.navigation_bagage_text}>Change place & preference..</Text> </View> ) }, drawerIcon: ({ tintColor }) => ( <Ionicons style={styles.icons} name="settings-outline" size={24}></Ionicons> ), } } }, AccountSecurity: { screen: AccountSecurityScreen, //screen: (props) => <AccountSecurityScreen {...props} ActionPanelActiveTab='EAS' />, navigationOptions: ({ navigation }) => { return { drawerLabel: () => null, drawerIcon: () => null, } } }, ProfilePhoto: { screen: ProfilePhotoScreen, //screen: (props) => <ProfilePhotoScreen {...props} />, navigationOptions: ({ navigation }) => { return { drawerLabel: () => null, drawerIcon: () => null, } } } }, { drawerPosition: 'left', drawerType: 'front', initialRouteName: 'Home', drawerBackgroundColor: '#FFF', drawerWidth: 300, contentComponent: CustomDrawerContentComponent, contentOptions: { activeTintColor: '#2EB6AE', inactiveTintColor: '#939393', } }); const AppStack = createStackNavigator({ Home: { screen: MyDrawerNavigator, navigationBarStyle: { navBarHidden: true }, navigationOptions: { headerShown: false, headerTransparent: true } }, YourAccounts: { screen: MyDrawerNavigator, navigationBarStyle: { navBarHidden: true }, navigationOptions: { headerShown: false, } }, Share: { screen: MyDrawerNavigator, navigationBarStyle: { navBarHidden: true }, navigationOptions: { headerShown: false, } }, Settings: { screen: MyDrawerNavigator, navigationBarStyle: { navBarHidden: true }, navigationOptions: { headerShown: false, } }, AccountSecurity: { screen: MyDrawerNavigator, navigationBarStyle: { navBarHidden: true }, navigationOptions: { headerShown: false, } }, ProfilePhoto: { screen: MyDrawerNavigator, navigationBarStyle: { navBarHidden: true }, navigationOptions: { headerShown: false, } }, }); const AuthStack = createStackNavigator({ Login: { screen: LoginScreen, navigationBarStyle: { navBarHidden: true }, navigationOptions: { headerShown: false, } }, }); const AppNavigator = createSwitchNavigator( { AppDashboard: AppStack, Auth: AuthStack, }, { initialRouteName: 'AppDashboard', }, ); const AppContainer = createAppContainer(AppNavigator); export default class Dashboard extends React.Component { render() { return ( this.props.isLoggedIn ? <AppContainer screenProps={{ username: this.props.username, usertypename: this.props.usertypename, isLoggedIn: this.props.isLoggedIn, profile_photo: this.props.profile_photo }} /> : <LoginScreen /> ); } }
Finally we will create a class which will contain Hamburger icon and toggleDrawer function so when you press on it sidebar toggle accordingly.
import React, { Component } from 'react'; import { Text, View, TouchableOpacity, Image } from 'react-native'; import { apiUrl } from "../config/constant"; export default class HeaderComponent extends Component { toggleDrawer = () => { this.props.navigationProps.toggleDrawer(); } render() { return ( <View> <TouchableOpacity style={{ position: 'absolute', top: 5, left: 10, display: 'flex', flexDirection: 'column', justifyContent: 'space-around', background: 'transparent', border: 'none', zIndex: 10 }} onPress={() => { this.props.navigation.openDrawer(); }} > <Image source={{ uri: apiUrl + 'assets/images/menu-rounded.png' }} style={{ width: 25, height: 25, marginLeft: -2 }} /> </TouchableOpacity> <View style={{ top: 9, alignContent: 'center', alignSelf: 'center' }}> <Text style={{ color: '#000080', alignContent: 'center', alignSelf: 'center' }}> {this.props.showName} </Text> </View> </View> ); } }