Amir
Amir

Reputation: 513

How to implement both DrawerNavigator and StackNavigator

I am developing an app using react-native-navigation and I want to have a StackNavigator and a DrawerNavigator in the project. So, I have implemented them in the app.js but the apps crashes giving this error "The development server returned response error with code: 500".I have implemented them separetly and it works but I couldn't implement them together.Any suggestion?

this is my code for app.js

import React, {
    Component
} from 'react';

import {
    StyleSheet,
    Text,
    View
} from 'react-native';

import {
    createStackNavigator,
    DrawerNavigator,
    DrawerItems
} from "react-navigation";

import {
    Container,
    Header,
    Content,
    Thumbnail,
    Button,
    Body
} from 'native-base';

import Profile from './components/Profile.js';
import Main from './components/Main.js';
import Login from './components/Login.js';
import Product from './components/Product.js';

export default class App extends Component {
    render() {
        return ( 
           <Navapp />
        );
    }
}

const styles = StyleSheet.create({
    // styles here
});

export const Drawer = DrawerNavigator({
    Main: {
        screen: Main
    },
    Profile: {
        screen: Profile
    },
}, {
initialRouteName: 'Main',
contentComponent: CustomDrawer,
drawerPosition: 'Left',
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});

export const CustomDrawer = (props) => ( 
    <Container>
        <Header style = {
            styles.headerStyle
        }>
            <Body style = {
                styles.bodyStyle
            }>
                <Thumbnail style = {
                    {
                        height: 100,
                        width: 100
                    }
                }
                source = {
                    require('../image/logo.png')
                }/> 
            </Body> 
        </Header>
        <Content>
            <DrawerItems { ...props}  /> 
        </Content > 
    </Container>
)

export const Navapp = createStackNavigator({
    Login: {
        screen: Login
    },
    Drawer: {
        screen: Drawer
    },
    Product: {
        screen: Product
    },
});

Upvotes: 9

Views: 14034

Answers (5)

Badal S
Badal S

Reputation: 567

Probably the way we can implement both Stack and Drawer Navigation has been made much simpler. Here you guys can refer to my code.

import * as React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { createDrawerNavigator } from "@react-navigation/drawer";
import MenuComponent from "../MenuComponent";
import DishDetailComponent from "../DishDetailComponent";
import HomeComponent from "../HomeComponent";

/**
 * @author BadalSherpa
 * @function HomeNavigation
 **/

const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();

const HomeNavigation = (props) => {
  return (
    <Stack.Navigator initialRouteName='Home'>
      <Stack.Screen name='Home' component={HomeComponent} />
      <Stack.Screen name='Menu' component={MenuComponent} />
      <Stack.Screen name='Dish-Detail' component={DishDetailComponent} />
    </Stack.Navigator>
  );
};

const MenuNavigation = (props) => {
  return (
    <Stack.Navigator initialRouteName='Home'>
      <Stack.Screen name='Menu' component={MenuComponent} />
    </Stack.Navigator>
  );
};

const DrawerNavigation = () => {
  return (
    <Drawer.Navigator>
      <Drawer.Screen name='Home' component={HomeNavigation} />  //Here is where we are combining Stack Navigator to Drawer Navigator
      <Drawer.Screen name='Menu' component={MenuNavigation} />
    </Drawer.Navigator>
  );
};

export default DrawerNavigation;

Then you can simple return this inside NavigationContainer which will have both Stack and Drawer Navigator working together.

<NavigationContainer>
      <HomeNavigation />
 </NavigationContainer>

Upvotes: 2

Glenn
Glenn

Reputation: 2206

This is a slightly different take where the drawer navigator controls a stack navigator. Each selection in the drawer will push a child stack element so there is a one-to-one match between the drawer and stack. This is more typical behavior in my experience. All but the home have a title with back navigation indicator.

import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';
import {
  CompositeNavigationProp,
  NavigationContainer,
} from '@react-navigation/native';
import {
  createStackNavigator,
  StackNavigationProp,
} from '@react-navigation/stack';
import HomeScreen from './HomeScreen';
import SettingsScreen from './SettingsScreen';
import {
  createDrawerNavigator,
  DrawerContentComponentProps,
  DrawerContentOptions,
  DrawerContentScrollView,
  DrawerItem,
  DrawerNavigationProp,
} from '@react-navigation/drawer';

type NoProps = Record<string, object>;
export type ScreenNavigationProps = CompositeNavigationProp<
  StackNavigationProp<NoProps>,
  DrawerNavigationProp<NoProps>
>;

export type DrawerProps = DrawerContentComponentProps<DrawerContentOptions>;
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator(); // https://reactnavigation.org/docs/stack-navigator/

/**
 * Render the content of the drawer.  When an item is selected
 * it closes the drawer and pushes an element on the stack nav.
 * @param props
 */
function CustomDrawerContent(props: DrawerProps) {
  const navigation = (props.navigation as unknown) as ScreenNavigationProps;

  const openScreen = (name: string) => () => {
    navigation.navigate('Home', {screen: name});
    navigation.closeDrawer();
  };

  return (
    <DrawerContentScrollView {...props}>
      {/* <DrawerItemList {...props} /> */}
      <DrawerItem label="Home" onPress={openScreen('Home')} />
      <DrawerItem label="Settings" onPress={openScreen('Settings')} />
    </DrawerContentScrollView>
  );
}

/**
 * Render the Home Stack Navigator.
 */
function HomeStack() {
  return (
    <Stack.Navigator initialRouteName="Home">
      <Stack.Screen
        name="Home"
        component={HomeScreen}
        options={{headerShown: false}}
      />
      <Stack.Screen name="Settings" component={SettingsScreen} />
    </Stack.Navigator>
  );
}

/**
 * Render the Home Drawer with a custom drawerContent.
 */
function HomeDrawer() {
  return (
    <Drawer.Navigator
      initialRouteName="Home"
      drawerContent={(props) => <CustomDrawerContent {...props} />}>
      <Drawer.Screen name="Home" component={HomeStack} />
    </Drawer.Navigator>
  );
}

const App = () => {
  return (
    <SafeAreaView style={styles.app}>
      <NavigationContainer>
        <HomeDrawer />
      </NavigationContainer>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  app: {flex: 1},
});

export default App;

The HomeScreen can provide a menu to open the drawer:

  const navigation = useNavigation<ScreenNavigationProps>();

  const openDrawer = () => {
    navigation.openDrawer();
  };

Upvotes: 0

farooq alam96
farooq alam96

Reputation: 57

same issue with me, Then i just change my emulator and update the version and it worked 100%.

Upvotes: 0

MattyCodes
MattyCodes

Reputation: 191

I had a very similar setup for my app, this is how I went about handling it. First I created a stack navigator with the routes that I wanted logged in users to see, and I place that navigator inside a drawer navigator (you can put more than one in there if you want). Finally I created my top-level navigator, whose initial route points to the login page; upon logging in I navigate the user to the second route, which points to my drawer navigator.

In practice it looks like this:

// Main Screens for Drawer Navigator
export const MainStack = StackNavigator({
  Dashboard: {
    screen: Dashboard,
    navigationOptions: {
      title: 'Dashboard',
      gesturesEnabled: false,
      headerLeft: null
    }
  },

  Notifications: {
    screen: Notifications,
    navigationOptions: {
      title: 'Notifications'
    }
  }
}, { headerMode: 'screen' } );

// Drawer Navigator
export const Drawer = DrawerNavigator({
  MainStack: {
    screen: MainStack
  }
});


// Main App Navigation
export const AppStack = StackNavigator({
  Login: {
    screen: Login,
    navigationOptions: {
      header: null,
      gesturesEnabled: false
    }
  },

  Drawer: {
    screen: Drawer,
    navigationOptions: {
      header: null,
      gesturesEnabled: false
    }
  }
}, { headerMode: 'none' } );

// In Your App.js
<AppStack />

Note that in the last stack navigator, the drawer screen has header set to null; this is because with nested stack navigators you can sometimes run into an issue where you'll have duplicate headers. This will hide the top-level navigator's header and let you show / customize the headers for your nested navigators.

Upvotes: 7

tuledev
tuledev

Reputation: 10317

This is how I use them

const HomeStackNavigator = StackNavigator(
  {
    Home: {
      screen: HomeScreen,
    },
    Chat: {
      screen: ChatScreen,
    },
  },
  {
    initialRouteName: 'Home',
    headerMode: 'screen',
  },
);

const MainDrawerNavigator = DrawerNavigator(
  {
    Home: {
      screen: HomeStackNavigator,
    },
  },
  {
    drawerOpenRoute: 'DrawerOpen',
    drawerCloseRoute: 'DrawerClose',
    drawerToggleRoute: 'DrawerToggle',
    contentComponent: SlideMenu,
    navigationOptions: {
      drawerLockMode: 'locked-closed',
    },
  },
);

Upvotes: 1

Related Questions