I am having an issue with duplicate headers and answers provided on stack overflow have not helped.
This is what I have tried, can anyone suggest a solution? I know I do not need all properties, but this is for the sake of demonstration of what did not help.
The header you are seeing on the screenshots comes from the screen component itself.
const Drawer = createDrawerNavigator();
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label="Logout" onPress={() => store.dispatch(logOut())} />
</DrawerContentScrollView>
);
}
const DrawerNavigator = () => {
return (
<Drawer.Navigator
screenOptions={{
headerShown: false,
unmountOnBlur: true,
headerTitle: false,
header: () => null,
}}
navigationOptions={{
headerMode: 'none',
headerVisible: false,
header: () => null,
}}
initialRouteName={Routes.Home}
drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name={Routes.Home} component={Home} />
<Drawer.Screen name={Routes.Locations} component={Locations} />
</Drawer.Navigator>
);
};
const Stack = createStackNavigator();
const Authenticated = () => {
return (
<Stack.Navigator initialRouteName="Nata">
<Stack.Screen
name="Drawer"
screenOptions={{
headerShown: false,
headerTitle: false,
}}
navigationOptions={{
headerMode: 'none',
headerVisible: false,
header: () => null,
}}
component={DrawerNavigator}
/>
<Stack.Screen name={Routes.AddLocation} component={AddLocation} />
</Stack.Navigator>
);
const Home = ({navigation}) => {
return (
<SafeAreaView style={[globalStyle.bgWhite, globalStyle.flex]}>
<Header
title={'Home'}
onLeftIconPress={() => navigation.goBack()}
onRightIconPress={() => navigation.toggleDrawer()}
/>
<ScrollView
style={[globalStyle.flex]}
contentContainerStyle={[
globalStyle.containerHorizontalPadding,
globalStyle.contentVerticalPadding,
]}
showsVerticalScrollIndicator={false}>
<View>
<Text>Home</Text>
</View>
</ScrollView>
</SafeAreaView>
);
};
export default Home;
This worked - thanks to everyone who took a look and here is a solution if anyone is looking for one still.
const DrawerNavigator = () => {
return (
<Drawer.Navigator
screenOptions={{
header: () => null,
}}
initialRouteName={Routes.Home}
drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name={Routes.Home} component={Home} />
<Drawer.Screen name={Routes.Locations} component={Locations} />
</Drawer.Navigator>
);
};
const Stack = createStackNavigator();
const Authenticated = () => {
return (
<Stack.Navigator
screenOptions={{
header: () => null,
headerShown: false,
}}
initialRouteName="Nata">
<Stack.Screen name="Drawer" options={{}} component={DrawerNavigator} />
<Stack.Screen name={Routes.AddLocation} component={AddLocation} />
</Stack.Navigator>
);
};
Related
App.js
function App() {
return (// Navigation container with stack order
<Provider store={store}>
<NavigationContainer>
<DrawerNavigator />
</NavigationContainer>
</Provider>
);
}
DrawerNavigator.js
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<Drawer.Navigator
drawerContentOptions={{
activeTintColor: '#e91e63',
itemStyle: {marginVertical: 5},
}}
drawerContent={(props) => <CustomSidebarMenu {...props} />}>
<Drawer.Screen
name="Authentication"
options={{drawerLabel: 'Authentication'}}
component={AuthStackNavigator}
/>
<Drawer.Screen
name="Symptom Checker
"
options={{drawerLabel: 'Symptom Checker'}}
component={MainStackNavigator}
/>
<Drawer.Screen
name="Reset Password
"
options={{drawerLabel: 'Reset Password'}}
component={ResetStackNavigator}
/>
</Drawer.Navigator>
);
};
export default DrawerNavigator;
StackNavigator.js
const Stack = createStackNavigator();
const AuthStackNavigator=() => {
return(
<Stack.Navigator initialRouteName='Authentication'>
<Stack.Screen name="Login" component={Login} options={{
headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)
}}/>
<Stack.Screen name="SignUp" component={Signup} options={{
headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)
}}/>
</Stack.Navigator>
)
}
const ResetStackNavigator=() => {
return(
<Stack.Navigator initialRouteName='Authentication'>
<Stack.Screen name="Reset Password" component={Reset_Password} options={{
headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)
}} />
</Stack.Navigator>
)
}
const MainStackNavigator = () => {
return (
<Stack.Navigator initialRouteName="SymptomChecker">
<Stack.Screen name="Symptom" component={Page1} options={{
title: 'Search Symptoms',headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
) //Set Header Title
}}/>
<Stack.Screen name='Diagnosis' component={Page2} options={{
title: 'Diagnosis', headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)//Set Header Tit
}}/>
<Stack.Screen name='Disease Component' component={DiseaseComponent} options={{
headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)
}} />
<Stack.Screen name='Summary' component={Summary} options={{
headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)
}} />
</Stack.Navigator>
);
}
export { MainStackNavigator, AuthStackNavigator, ResetStackNavigator }
I know to toggle drawer I will be using navigation.toggleDrawer(). The issue is i don't know how can i gain the navigation prop inside each of my stack navigators.
I would be glad to accept any advice.
..........................................................................................
You can use useNavigation:
import { useNavigation } from '#react-navigation/native';
const MainStackNavigator = () => {
const navigation = useNavigation();
return (
<Stack.Navigator initialRouteName="SymptomChecker">
<Stack.Screen name="Symptom" component={Page1} options={{
title: 'Search Symptoms',headerLeft: () => (
<Icon
onPress={()=>navigation.toggleDrawer()}
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
) //Set Header Title
}}/>
<Stack.Screen name='Diagnosis' component={Page2} options={{
title: 'Diagnosis', headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)//Set Header Tit
}}/>
<Stack.Screen name='Disease Component' component={DiseaseComponent} options={{
headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)
}} />
<Stack.Screen name='Summary' component={Summary} options={{
headerLeft: () => (
<Icon
name='ei-navicon'
type='evilicon'
color='#517fa4'
/>
)
}} />
</Stack.Navigator>
I'm using StackNavigator, inside TabNavigator, inside Drawer Navigator.
Trying to redirect to nested Stacks but returns error.
Warning: React has detected a change in the order of Hooks called by StackNavigator. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks:
TypeError: undefined is not an object (evaluating 'prevDeps.length')
What's wront with that?
Why it doesnt redirect to stack.screen below main screen?
my redirect:
<TouchableOpacity style={styles.accessButton} onPress={() => navigation.navigate('Home', {
screen: 'Events'
})}>
My main.js (navigator)
return (
<NavigationContainer theme={NavigationTheme} ref={navigationRef}>
<StatusBar barStyle={darkMode ? 'light-content' : 'dark-content'} />
<Drawer.Navigator
drawerStyle={{ width: '100%' }}
drawerContent={(props) => <DrawerContent {...props} />}
>
<Drawer.Screen name="Startup" component={IndexStartupContainer} />
{isApplicationLoaded && BeforeLogin != null && (
<Drawer.Screen name="Main" component={BeforeLogin} />
)}
</Drawer.Navigator>
</NavigationContainer>
)
my tabbar navigator:
return (
<Tab.Navigator tabBarOptions={{showLabel: false}} lazy>
<Tab.Screen name="Home" component={HomeNavigator}
options={{
tabBarIcon: ({size,focused,color}) => {
return (
<AntDesign name="home" size={39} color={colors.text} />
);
},
}}
/>
<Tab.Screen name="SearchNavigator" component={SearchNavigator}
options={{
tabBarIcon: ({size,focused,color}) => {
return (
<AntDesign name="search1" size={39} color={colors.text} />
);
},
}}
/>
<Tab.Screen name="FAQNavigator" component={FAQNavigator}
options={{
tabBarIcon: ({size,focused,color}) => {
return (
<AntDesign name="questioncircleo" size={39} color={colors.text} />
);
},
}}
/>
<Tab.Screen name="ContactNavigator" component={ContactNavigator}
options={{
tabBarIcon: ({size,focused,color}) => {
return (
<Feather name="phone" size={39} color={colors.text} />
);
},
}}
/>
</Tab.Navigator>
)
and my HomeNavigator:
const HomeNavigator = ({ navigation }) => {
const Stack = createStackNavigator()
const { t } = useTranslation()
return (
<Stack.Navigator>
<Stack.Screen
options={headerStyle_1}
name='Index'
title={t('title.homepage')}
component={HomepageController}
/>
<Stack.Screen
options={headerStyle_1}
name='Events'
title={t('title.events')}
component={EventsController}
/>
</Stack.Navigator>
)
}
I am trying to have a tab bar and each tab bar has its own stack navigator. Three tabs that i have are
Home
Profile
Settings
I want to show these three options in the drawer also. I have created a drawer but only tapping home shows the tab bar. I want to show tab bar just like if you press of profile tab and tab bar remains there.
Here is my code:
const HomeStackNavigator = createStackNavigator();
export const HomeNavigator = () => {
return (
<HomeStackNavigator.Navigator screenOptions={defaultNavOptions}>
<HomeStackNavigator.Screen
name="Home"
component={HomeScreen}
options={homeScreenOptions}
/>
<HomeStackNavigator.Screen
name="Details"
component={DetailsScreen}
options={detailsScreenOptions}
/>
</HomeStackNavigator.Navigator>
);
};
const ProfileStackNavigator = createStackNavigator();
export const ProfileNavigator = () => {
return (
<ProfileStackNavigator.Navigator screenOptions={defaultNavOptions}>
<ProfileStackNavigator.Screen
name="Profile"
component={ProfileScreen}
options={profileScreenOptions}
/>
<ProfileStackNavigator.Screen
name="EditProfile"
component={EditProfileScreen}
options={editProfileScreenOptions}
/>
</ProfileStackNavigator.Navigator>
);
};
const SettingsStackNavigator = createStackNavigator();
export const SettingsNavigator = () => {
return (
<SettingsStackNavigator.Navigator screenOptions={defaultNavOptions}>
<SettingsStackNavigator.Screen
name="Settings"
component={SettingsScreen}
options={settingsScreenOptions}
/>
<SettingsStackNavigator.Screen
name="AccountDetail"
component={AccountDetailsScreen}
options={accountDetailsScreenOptions}
/>
</SettingsStackNavigator.Navigator>
);
};
const HomeTabNavigator = createBottomTabNavigator();
export const TabNavigator = () => {
return (
<HomeTabNavigator.Navigator screenOptions={defaultNavOptions}>
<HomeTabNavigator.Screen
name="Home"
component={HomeNavigator}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<HomeTabNavigator.Screen
name="Profile"
component={ProfileNavigator}
options={{
tabBarLabel: 'Profile',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="face-profile" color={color} size={size} />
),
}}
/>
<HomeTabNavigator.Screen
name="Settings"
component={SettingsNavigator}
options={{
tabBarLabel: 'Settings',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account-settings" color={color} size={size} />
),
}}
/>
</HomeTabNavigator.Navigator>
);
};
const AppDrawer = createDrawerNavigator();
export const Drawer = () => {
return(
<AppDrawer.Navigator initialRouteName="Home">
<AppDrawer.Screen name="Home" component={TabNavigator} />
<AppDrawer.Screen name="Profile" component={ProfileNavigator} />
<AppDrawer.Screen name="Settings" component={SettingsNavigator} />
</AppDrawer.Navigator>
)
};
My goal is to have tabs all the time. Tabs should hide only if we go to the detail page of any of the tabs.
You can make your TabNavigator a screen of a stack navigator which is a screen of your drawer navigator and pass a custom drawer component to your drawer navigator:
const AppDrawer = createDrawerNavigator();
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
const HomeTabNavigator = createBottomTabNavigator();
export const TabNavigator = () => {
return (
<HomeTabNavigator.Navigator>
<HomeTabNavigator.Screen
name="Home"
component={HomeScreen}
options={{
tabBarLabel: 'Home',
}}
/>
<HomeTabNavigator.Screen
name="Profile"
component={ProfileScreen}
options={{
tabBarLabel: 'Profile',
}}
/>
<HomeTabNavigator.Screen
name="Settings"
component={SettingsScreen}
options={{
tabBarLabel: 'Settings',
}}
/>
</HomeTabNavigator.Navigator>
);
};
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItem
label="Home"
onPress={() => props.navigation.navigate('Home')}
/>
<DrawerItem
label="Profile"
onPress={() => props.navigation.navigate('Profile')}
/>
<DrawerItem
label="Settings"
onPress={() => props.navigation.navigate('Settings')}
/>
</DrawerContentScrollView>
);
}
function getHeaderTitle(route) {
return getFocusedRouteNameFromRoute(route) ?? 'Home';
}
const StackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Tabs"
component={TabNavigator}
options={({route}) => ({
headerTitle: getHeaderTitle(route),
})}
/>
<Stack.Screen name="EditProfile" component={EditProfileScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="AccountDetail" component={AccountDetailsScreen} />
</Stack.Navigator>
);
};
export const Drawer = () => {
return (
<AppDrawer.Navigator
initialRouteName="Home"
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<AppDrawer.Screen name="Stack" component={StackNavigator} />
</AppDrawer.Navigator>
);
};
function App() {
return (
<NavigationContainer>
<Drawer />
</NavigationContainer>
);
}
The screens you don't want to show the tabs for can be put inside the stack navigator outside of the tab navigator.
Sources:
https://reactnavigation.org/docs/drawer-navigator/#providing-a-custom-drawercontent.
https://reactnavigation.org/docs/screen-options-resolution/#setting-parent-screen-options-based-on-child-navigators-state.
Be sure to import DrawerItem, DrawerContentScrollView from #react-navigation/drawer and getFocusedRouteNameFromRoute from #react-navigation/native.
Getting the following Issue when I use Drawer. Stack and Tab are working fine without Drawer.
Does anyone know what is going on here and can help me?
enter image description here
Here is Navigator File some Code lines:
const Stack = createStackNavigator();
const FavStack = createStackNavigator();
const FilterStack = createStackNavigator();
const Tab =
Platform.OS === "android"
? createMaterialBottomTabNavigator()
: createBottomTabNavigator();
const defaultScreenOptions = {
headerStyle: { backgroundColor: colors.primary },
headerTintColor: "white",
};
function MealsNavigator() {
return (
<Stack.Navigator screenOptions={defaultScreenOptions}>
<Stack.Screen name="Meals Categories" component={CategoriesScreen} />
<Stack.Screen name="Profile" component={CategoryMealScreen} />
<Stack.Screen name="Details" component={MealDetailsScreen} />
</Stack.Navigator>
);
}
function FavStackNavigator() {
return (
<FavStack.Navigator screenOptions={defaultScreenOptions}>
<FavStack.Screen name="Favourites" component={FavouritesScreen} />
<FavStack.Screen name="Details" component={MealDetailsScreen} />
</FavStack.Navigator>
);
}
function MealsFavTabNavigator() {
return (
<Tab.Navigator
tabBarOptions={{ activeTintColor: colors.accent }}
shifting={true}
>
<Tab.Screen
name="All"
component={MealsNavigator}
options={{
tabBarLabel: "Meals",
tabBarIcon: (tabInfo) => (
<Ionicons name="ios-restaurant" size={25} color={tabInfo.color} />
),
tabBarColor: colors.primary,
}}
/>
<Tab.Screen
name="Favourites"
component={FavStackNavigator}
options={{
tabBarIcon: (tabInfo) => (
<Ionicons name="ios-star" size={25} color={tabInfo.color} />
),
tabBarColor: colors.accent,
}}
/>
</Tab.Navigator>
);
}
function FilterStackNavigator() {
return (
<FilterStack.Navigator>
<FilterStack.Screen name="Filters" component={FilterScreen} />
</FilterStack.Navigator>
);
}
const Drawer = createDrawerNavigator();
function MenuNavigator() {
return (
<Drawer.Navigator>
<Drawer.Screen name="MealFavs" component={MealsFavTabNavigator} />
<Drawer.Screen name="Filters" component={FilterStackNavigator} />
</Drawer.Navigator>
);
}
export default MenuNavigator;
Here is App.js few Code lines:
export default function App() {
const [fontLoaded, setFontLoaded] = useState(false);
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={() => setFontLoaded(true)}
onError={(err) => console.log(err)}
/>
);
}
return <NavigationContainer><MealsNavigator /></NavigationContainer>
}
Code is not giving error without Drawer, It is working exactly fine with Stack and Tab Navigators!
I got a React-Navigation 5 drawer menu working using gesture, but I also want to add an icon on the right side of the header to toggle the drawer menu.
I have the navigation setup in my App.js like this:
import {NavigationContainer, DrawerActions} from '#react-navigation/native';
//....... other imports
const HomeStack = createStackNavigator();
const HomeStackScreens = () => (
<HomeStack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#5C6BC0',
},
headerTintColor: '#fff',
headerRight: () => {
return (
<TouchableOpacity
onPress={() => DrawerActions.toggleDrawer()}>
<Icon name="bars" color="#FFF" size={18} />
</TouchableOpacity>
);
},
}}>
<HomeStack.Screen
name="Home"
component={HomeScreen}
options={{
header:({scene, previous, navigation}) => {
return (
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<Icon name="bars" color="#FFF" size={18} />
</TouchableOpacity>
);
}
}}
/>
<HomeStack.Screen name="Login" component={Login} />
<HomeStack.Screen name="Register" component={Register} />
</HomeStack.Navigator>
);
const ProfileStack = createStackNavigator();
const ProfileStackScreens = () => (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={Profile} />
</ProfileStack.Navigator>
);
const SettingStack = createStackNavigator();
const SettingStackScreens = () => (
<SettingStack.Navigator>
<SettingStack.Screen name="Profile" component={Profile} />
</SettingStack.Navigator>
);
const Drawer = createDrawerNavigator();
const DrawerScreens = () => (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomeStackScreens} />
<Drawer.Screen name="Profile" component={ProfileStackScreens} />
<Drawer.Screen name="Settings" component={SetttingStackScreens} />
</Drawer.Navigator>
);
class MyApp extends React.Component {
render() {
return (
<NavigationContainer>
<DrawerScreens />
</NavigationContainer>
);
}
}
export default MyApp;
All my others screen are in the form "export default class ScreenName extends React.Component". They are imported in App.js to setup the navigation. The initial screen is Home. The icon is showing correctly on the right side of the header. Calling "DrawerActions.toggleDrawer()" directly does nothing.
I tried "this.props.navigation.toggleDrawer()", and it throws error because "this.props" is undefined.
How can I invoke toggleDrawer() with such a navigation setup? Any help is really appreciated!
Here is the final solution I come up with that requires minimal changes to my original code. The key is to receive "navigation" in screenOptions or options, then I can call navigation methods in the children of screenOptions/options.
<HomeStack.Navigator
screenOptions={({navigation}) => ({
headerStyle: {
backgroundColor: '#5C6BC0',
},
headerTintColor: '#fff',
headerRight: () => {
return (
<TouchableOpacity
style={{paddingRight: 8}}
onPress={() => navigation.toggleDrawer()}>
<Icon name="bars" color="#FFF" size={18} />
</TouchableOpacity>
);
},
})}>