'React-Native - no header on one of the screen (Stack + Drawer Navigation)

My navigation file is as follows. All the screens that are registered with the Stack navigator have a header. The one screen that is registered as the second option with the Drawer navigator has no header at all (OrdersScreen). I tried adding its entry under the Stack navigator as well but it didn't change anything. The setOptions in the OrderScreen have no effect as no header is displayed.

import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createDrawerNavigator } from '@react-navigation/drawer';

import { Platform } from 'react-native';

import Colors from '../constants/Colors';

import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetailScreen from "../screens/shop/ProductDetailScreen";
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";


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


const AppNavigation = () => {
  return(
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="ShopNavigation">
        <Drawer.Screen name="Products" component={ShopNavigation}/>
        <Drawer.Screen name="Orders" component={OrdersScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
};

const ShopNavigation = () => {
  return(
      <Stack.Navigator>
        <Stack.Screen
          name="Products"
          component={ProductsOverviewScreen}
          options={{
            title: 'All Products',
            headerStyle: {
              backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
            },
            headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
            headerTitleStyle: {
              fontFamily: 'open-sans-bold'
            },
            headerBackTitleStyle: {
              fontFamily: 'open-sans'
            }
          }}
        />
        <Stack.Screen name="Product Details" component={ProductDetailScreen} />
        <Stack.Screen name="Cart" component={CartScreen} />
      </Stack.Navigator>
  );
};

export default AppNavigation;

The OrderScreen is as follows:

import React, {useEffect} from 'react';
import {FlatList, View, Platform, Text, Button} from 'react-native';
import { useSelector } from 'react-redux';
import {HeaderButtons, Item} from "react-navigation-header-buttons";
import CustomHeaderButton from "../../components/UI/HeaderButton";

const OrdersScreen = (props) => {
  const orders = useSelector(state => state.orders.orders);

  useEffect(() => {
    props.navigation.setOptions({
      title: 'Your Orders',
      headerLeft: () => (
        <HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
          <Item
            title="Orders"
            iconName={Platform.OS === 'android' ? 'md-menu' : 'ios-menu'}
            onPress={() => props.navigation.toggleDrawer()}
          />
        </HeaderButtons>
        ),
    });
  },[])


  return(
    <View>
      <Text>Orders screens</Text>
      <Text>some text</Text>
      <Text>Yet another</Text>
      <Button title="toggle Drawer" onPress={() => props.navigation.toggleDrawer()} />
    </View>
  );
};


export default OrdersScreen; 

The ProductsOverviewScreen, which is the default screen on the Stack navigation works fine with the header button and the header icons.

import React, { useEffect } from 'react';
import { FlatList, Platform } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import ProductItem from "../../components/ProductItem";
import { addToCart } from "../../redux/cartSlice";
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import CustomHeaderButton from "../../components/UI/HeaderButton";

const ProductsOverviewScreen = ({ navigation }) => {
  const products = useSelector(state => state.products.availableProducts);
  const dispatch = useDispatch();

  useEffect(() => {
    navigation.setOptions({
      headerLeft: () => (
        <HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
          <Item
            title="Orders"
            iconName={Platform.OS === 'android' ? 'md-menu' : 'ios-menu'}
            onPress={() => navigation.toggleDrawer()}
          />
        </HeaderButtons>
      ),
      headerRight: () => (
        <HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
          <Item
            title="Cart"
            iconName={Platform.OS === 'android' ? 'md-cart' : 'ios-cart'}
            onPress={() => navigation.navigate('Cart')}
          />
        </HeaderButtons>
      )
      });
    }, [])


  return(
    <FlatList
      data={products}
      renderItem={({item}) =>
        <ProductItem
          image={item.imageUrl}
          title={item.title}
          price={item.price}
          onViewDetail={() => { navigation.navigate('Product Details', { productId: item.id, productTitle: item.title  })}}
          onAddToCart={() => dispatch(addToCart(item))}
        />
      }
      />
  );
};



export default ProductsOverviewScreen;

EDIT: Thanks. I've done as you said (only one item in the Drawer Navigator and moved OrdersScreen to the StackNavigator. I've added a custom content to the Drawer, as well. The only thing that does not work now is when I open the Drawer from the OrdersScreen (that is accessed through Drawer Custom Content), when I click on 'Products' (default and only Drawer item), nothing happens (The drawer hides but remains on the OrdersScreen). Here's the updated Navigation file

import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem, } from '@react-navigation/drawer';

import { Platform } from 'react-native';

import Colors from '../constants/Colors';

import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetailScreen from "../screens/shop/ProductDetailScreen";
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";


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


const CustomDrawerContent = (props) => {
  return (
    <DrawerContentScrollView {...props}>
      <DrawerItemList {...props} />
      <DrawerItem label="Orders" onPress={() => props.navigation.navigate('Orders')} />
    </DrawerContentScrollView>
  );
}



const AppNavigation = () => {
  return(
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="ShopNavigation" drawerContent={props => <CustomDrawerContent {...props} />}>
        <Drawer.Screen name="Products" component={ShopNavigation}/>
      </Drawer.Navigator>
    </NavigationContainer>
  );
};

const ShopNavigation = () => {
  return(
      <Stack.Navigator>
        <Stack.Screen
          name="Products"
          component={ProductsOverviewScreen}
          options={{
            title: 'All Products',
            headerStyle: {
              backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
            },
            headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
            headerTitleStyle: {
              fontFamily: 'open-sans-bold'
            },
            headerBackTitleStyle: {
              fontFamily: 'open-sans'
            }
          }}
        />
        <Stack.Screen name="Product Details" component={ProductDetailScreen} />
        <Stack.Screen name="Cart" component={CartScreen} />
        <Stack.Screen name="Orders" component={OrdersScreen} />
      </Stack.Navigator>
  );
};

export default AppNavigation;

EDIT2: So now I've got two DrawItems in the CustomDrawer and they work fine from both 'All Products' and 'Orders'. The issue I'm having is that I cannot get rid of the default DrawerNavigation entry (not custom content):

<Drawer.Screen name="ShopNavigation" component={ShopNavigation}/>

as that would mean that Drawer.Navigator does not have any children. By default it has to default to the StackNavigator, doesn't it? You suggested that I should have all the entries coming from CustomDrawerContent. At the moment, the drawer has the following items:

  • ShopNavigation (default, does not work, when clicked from 'Orders'.)
  • All Products (customcontent, works fine everywhere)
  • Orders (Custom content, works fine everywhere)

const CustomDrawerContent = (props) => {
  return (
    <DrawerContentScrollView {...props}>
      <DrawerItemList {...props} />
      <DrawerItem label="All Products" onPress={() => props.navigation.navigate('All Products')} />
      <DrawerItem label="Orders" onPress={() => props.navigation.navigate('Orders')} />
    </DrawerContentScrollView>
  );
}



const AppNavigation = () => {
  return(
    <NavigationContainer>
      <Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
        <Drawer.Screen name="ShopNavigation" component={ShopNavigation}/>
      </Drawer.Navigator>
    </NavigationContainer>
  );
};

const ShopNavigation = () => {
  return(
      <Stack.Navigator>
        <Stack.Screen
          name="All Products"
          component={ProductsOverviewScreen}
          options={{
            title: 'All Products',
            headerStyle: {
              backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
            },
            headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
            headerTitleStyle: {
              fontFamily: 'open-sans-bold'
            },
            headerBackTitleStyle: {
              fontFamily: 'open-sans'
            }
          }}
        />
        <Stack.Screen name="Product Details" component={ProductDetailScreen} />
        <Stack.Screen name="Cart" component={CartScreen} />
        <Stack.Screen name="Orders" component={OrdersScreen} />
      </Stack.Navigator>
  );
};


Solution 1:[1]

This happens because the header is added to screens within a stack navigator, not to screens that are part of a drawer navigator. If you want the header to be displayed on all screens I recomend that your drawer navigator has only one screen that is actually a stack navigator and that will work. In this case you would also need a custom drawer component to display the items you want since the default will only have one entry.

Solution 2:[2]

To control the visibility of header in different screen of drawer navigator, you can use screenOptions to hide and show the header to particular drawer screen.

<Drawer.Navigator   screenOptions={({route}) => ({
                        headerShown: route.name === "screen1" ?false : true
                    })}>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nicolás Longhi
Solution 2 Khim Bahadur Gurung