'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 |
