I have a fairly simple React Native app that I am using to showcase a custom component library. I recently upgraded the app from React Native version 0.67.2 to 0.70.6. React Navigation is still on version 5.x (latest is 6.x). My issue is that when I attempt to open my navigation drawer, I see a shadow over my home screen, but the drawer does not appear. The ellipsis menu also fails to appear.
Here is the home screen on app load:
Here is the home screen when I tap the hamburger menu:
I have narrowed down the problem to my custom header component. When I comment out the Actions in the header, including the children, the drawer works.
Here is the home page:
HomeStack.tsx
:
import { CustomHeader } from '@custom-components/Header';
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
import { Appbar, Menu, Divider, useTheme } from 'react-native-paper';
import { HomeScreen } from '../screens';
const Stack = createStackNavigator();
const HomeStack = (): JSX.Element => {
const theme: ReactNativePaper.Theme = useTheme();
const [isMenuVisible, setMenuVisible] = React.useState(false);
const openMenu = () => setMenuVisible(true);
const closeMenu = () => setMenuVisible(false);
return (
<Stack.Navigator
headerMode="float"
screenOptions={{
header: () => (
<CustomHeader title="Home">
<Menu
visible={isMenuVisible}
onDismiss={closeMenu}
anchor={
<Appbar.Action
icon="dots-vertical"
testID="header-action-1"
touchSoundDisabled={false}
onPress={openMenu}
color={theme.colors.text}
/>
}
>
<Menu.Item onPress={() => {}} title="Item 1" />
<Menu.Item onPress={() => {}} title="Item 2" />
<Menu.Item onPress={() => {}} title="Item 3" />
</Menu>
</CustomHeader>
),
}}
>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
);
};
export default HomeStack;
And the header:
CustomHeader.tsx
import { DrawerActions, useNavigation } from '@react-navigation/native';
import React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import { Appbar, useTheme } from 'react-native-paper';
import { common } from '../theme/colors';
export type CustomHeaderProps = {
title: string;
subtitle?: string;
scaleMenuIcon?: number;
headerHeight?: number;
titleSize?: number;
subtitleSize?: number;
children?: React.ReactNode;
backgroundColor?: string;
color?: string;
};
export const CustomHeader = ({
title,
subtitle,
scaleMenuIcon,
titleSize = 20,
subtitleSize = 15,
headerHeight,
children,
backgroundColor = common.offWhite,
color = common.black,
}: CustomHeaderProps): JSX.Element => {
const navigation = useNavigation();
const theme = useTheme();
const openMenu = () => {
navigation.dispatch(DrawerActions.openDrawer());
};
return (
<Appbar.Header style={
backgroundColor: theme.dark ? undefined : backgroundColor,
height: headerHeight
}>
<Appbar.Action
icon="menu"
testID="header-button"
style={styles.menuIcon}
onPress={openMenu}
touchSoundDisabled={true}
size={scaleMenuIcon}
color={theme.dark ? undefined : color}
/>
<Appbar.Content
testID="appbar-content"
color={theme.dark ? undefined : color}
style={styles.headerText}
title={title}
titleStyle={{ fontSize: titleSize }}
subtitle={subtitle}
subtitleStyle={{ fontSize: subtitleSize }}
/>
// If I comment out this View, the drawer appears.
<View style={styles.headerImageText}>
{children && (
<View testID="appbar-actions" style={styles.children}>
{children}
</View>
)}
</View>
</Appbar.Header>
);
};
const styles = StyleSheet.create({
children: {
flexDirection: 'row',
justifyContent: 'flex-end',
paddingRight: 30,
...Platform.select({
ios: {
left: -10,
},
android: {
left: 0,
},
}),
},
headerImageText: {
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'flex-start',
paddingLeft: 10,
},
headerText: {
flexGrow: 6,
flexShrink: 1,
fontSize: 20,
fontWeight: 'bold',
justifyContent: 'center',
left: -10,
letterSpacing: 1,
},
menuIcon: {
left: 10,
},
});