I am creating a react native application where I have a component app header that has a menu icon and when we press that the drawer should open but it is giving error that -
ERROR TypeError: navigation.toggleDrawer is not a function (it is undefined), js engine: hermes
Here is that component where I am using toggleDrawer() -
import { View, Text, StyleSheet, Image, TouchableOpacity } from 'react-native'
import React from 'react'
import { widthPercentageToDP as wp } from 'react-native-responsive-screen'
import { background_color, light_red, primary_color } from '../util/Colors'
import Ionicons from 'react-native-vector-icons/Ionicons'
import AntDesign from 'react-native-vector-icons/AntDesign'
import { useNavigation } from '@react-navigation/native'
export default function AppHeader({screenName}) {
const navigation=useNavigation();
const handleWallet=()=>{
navigation.navigate('Wallet');
}
const handleLanguage=()=>{
}
const handleSupport=()=>{
navigation.navigate('Customer Support')
}
const handleMenu=()=>{
navigation.toggleDrawer();
}
return (
<View style={styles.container}>
<TouchableOpacity onPress={handleMenu}>
<Ionicons name='menu' size={30} color={background_color}/>
</TouchableOpacity>
<Text style={styles.title}>{screenName}</Text>
<View style={styles.sideIcon}>
<TouchableOpacity onPress={handleWallet}>
<Image source={require('../Assets/wallet.png')} style={{ tintColor: background_color, width: 24, height:24 }} />
</TouchableOpacity>
<TouchableOpacity onPress={handleLanguage}>
<Image source={require('../Assets/language.png')} style={{ tintColor: background_color, width: 24, height:24 }} />
</TouchableOpacity>
<TouchableOpacity onPress={handleSupport}>
<Image source={require('../Assets/support.png')} style={{ tintColor: background_color, width: 24, height:24 }} />
</TouchableOpacity>
</View>
</View>
)
}
const styles=StyleSheet.create({
container:{
width:wp(100),
height:55,
backgroundColor:primary_color,
alignItems:"center",
flexDirection:"row",
paddingHorizontal:20,
gap:20,
marginBottom:8
},
title:{
color:background_color,
fontSize:18,
fontWeight:"bold"
},
sideIcon:{
position:"absolute",
right:0,
gap:18,
flexDirection:"row",
alignItems:"center",
marginRight:20
}
})
And also I have two more buttons wallet and customer support they are also not working and showing error -
The action 'NAVIGATE' with payload {"name":"Customer Support"} was not handled by any navigator.
Do you have a screen named 'Customer Support'?
If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
This is a development-only warning and won't be shown in production.
According to me my Navigation is set up correctly here is Navigation.js -
import {Image} from 'react-native'
import React, { useEffect, useState } from 'react'
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import LogInviaPhone from '../Screens/LogInviaPhone';
import LogInviaEmail from '../Screens/LogInviaEmail';
import OTPScreen from '../Screens/OTPScreen';
import OTPScreenEmail from '../Screens/OTPScreenEmail';
import HomeScreen from '../Screens/HomeScreen';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Call from '../Screens/Call';
import Live from '../Screens/Live';
import Chat from '../Screens/Chat';
import Pooja from '../Screens/Pooja';
import FontAwesome from 'react-native-vector-icons/FontAwesome'
import Feather from 'react-native-vector-icons/Feather'
import Ionicons from 'react-native-vector-icons/Ionicons'
import AntDesign from 'react-native-vector-icons/AntDesign'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import MaterialIcons from 'react-native-vector-icons/MaterialIcons'
import Foundation from 'react-native-vector-icons/Foundation'
import { background_color, primary_color, secondary_color } from '../util/Colors';
import History from '../Screens/History';
import Wallet from '../Screens/Wallet';
import Favorite from '../Screens/Favorite';
import Refer from '../Screens/Refer';
import FreeService from '../Screens/FreeService';
import AstrologerRegistration from '../Screens/AstrologerRegistration';
import CustomerSupport from '../Screens/CustomerSupport';
import Mall from '../Screens/Mall';
import Settings from '../Screens/Settings';
import MyFollowing from '../Screens/MyFollowing';
import CustomDrawer from './CustomDrawer';
import { appName } from '../util/AppDetails';
// import DeviceInfo from 'react-native-device-info';
// import * as RNLocalize from 'react-native-localize';
// import { getCountry } from "react-native-localize";
// import ISO3166 from 'iso-3166-1-alpha-2';
// import {NetworkInfo} from 'react-native-network-info';
// import axios from 'axios'
import { widthPercentageToDP as wp } from 'react-native-responsive-screen';
import Share from '../Screens/Share';
import RateUs from '../Screens/RateUs';
import UserDetails from '../Screens/UserDetails';
import AppHeader from '../Components/AppHeader';
import AsyncStorage from '@react-native-async-storage/async-storage';
const Stack=createNativeStackNavigator();
const Tab=createBottomTabNavigator();
const Drawer=createDrawerNavigator();
const MainTab=()=>{
return(
<Tab.Navigator screenOptions={{
tabBarStyle:{
backgroundColor:background_color,
height:55,
paddingBottom:5,
paddingTop:5,
paddingHorizontal:3
},
tabBarActiveTintColor:"black",
tabBarLabelStyle:{
fontSize:12
},
headerShown:false
}}>
<Tab.Screen name='Home' component={HomeScreen} options={{
tabBarIcon:({ color, size }) => (<Feather name="home" size={20} color={color} />),
}}/>
<Tab.Screen name='Call' component={Call} options={{
tabBarIcon:({ color, size }) => (<Ionicons name="call-outline" size={20} color={color} />),
}}/>
<Tab.Screen name='Live' component={Live} options={{
tabBarIcon:({ color, size }) => (<Feather name="video" size={20} color={color} />),
}}/>
<Tab.Screen name='Chat' component={Chat} options={{
tabBarIcon:({ color, size }) => (<Ionicons name="chatbubbles-outline" size={20} color={color} />),
}}/>
<Tab.Screen name='Pooja' component={Pooja} options={{
tabBarIcon: ({ color, size }) => (
<Image source={require('../Assets/kalash.png')} style={{ tintColor: color, width: 22, height: 22 }} />
)
}}/>
<Tab.Screen name='Mall' component={Mall} options={{
tabBarIcon: ({ color, size }) => (<MaterialCommunityIcons name="shopping" size={20} color={color} />)
}}/>
</Tab.Navigator>
)
}
const MainDrawer=({navigation})=>{
return(
<Drawer.Navigator screenOptions={{
drawerContentStyle:{
height:10,
},
drawerLabelStyle:{
marginVertical:-8,
paddingLeft:10,
textAlign:"left",
marginLeft:-15,
},
drawerStyle:{
width:wp(80)
},
drawerActiveBackgroundColor:secondary_color,
drawerActiveTintColor:"black",
headerShown:false
}}
drawerContent={props=> <CustomDrawer {...props}/>}>
<Drawer.Screen name='Home Screen' component={MainTab} options={{
title:" Home",
drawerIcon:({ color, size }) => (<Foundation name="home" size={20} color={color} />),
}}/>
<Drawer.Screen name='Chat' component={Chat} options={{
title:"Chat with Astrologer",
drawerIcon:({ color, size }) => (<Ionicons name="chatbubbles" size={20} color={color} />),
}}/>
<Drawer.Screen name='Call' component={Call} options={{
title:"Call Astrologer",
drawerIcon:({ color, size }) => (<Ionicons name="call" size={20} color={color} />)
}}/>
<Drawer.Screen name='Live' component={Live} options={{
title:"Astrologer Live",
drawerIcon:({ color, size }) => (<Ionicons name="videocam" size={20} color={color} />)
}}/>
<Drawer.Screen name='Pooja' component={Pooja} options={{
title:"Book a Pooja",
drawerIcon:({ color, size }) => (
<Image source={require('../Assets/kalash.png')} style={{ tintColor: color, width: 20, height: size }} />
)
}}/>
<Drawer.Screen name='History' component={History} options={{
title:"Order History",
drawerIcon:({ color, size }) => (<MaterialIcons name="history" size={20} color={color} />)
}}/>
<Drawer.Screen name='Wallet' component={Wallet} options={{
title:"Wallet Transaction",
drawerIcon:({ color, size }) => (<Ionicons name="wallet" size={20} color={color} />)
}}/>
<Drawer.Screen name='Favorite' component={Favorite} options={{
drawerIcon:({ color, size }) => (<MaterialIcons name="favorite" size={20} color={color} />)
}}/>
<Drawer.Screen name='Refer' component={Refer} options={{
title:"Refer to Friend",
drawerIcon:({ color, size }) => (<MaterialCommunityIcons name="share" size={20} color={color} />)
}}/>
<Drawer.Screen name='Astro Mall' component={Mall} options={{
drawerIcon:({ color, size }) => (<MaterialCommunityIcons name="shopping" size={20} color={color} />)
}}/>
<Drawer.Screen name='My Followings' component={MyFollowing} options={{
drawerIcon:({ color, size }) => (
<Image source={require('../Assets/following.png')} style={{ tintColor: color, width: 20, height: 20 }} />
)
}}/>
<Drawer.Screen name='Customer Support' component={CustomerSupport} options={{
drawerIcon:({ color, size }) => (<AntDesign name="customerservice" size={20} color={color} />)
}}/>
<Drawer.Screen name='Free Service' component={FreeService} options={{
drawerIcon:({ color, size }) => (
<Image source={require('../Assets/free.png')} style={{ tintColor: color, width: 20, height: 20 }} />
)
}}/>
<Drawer.Screen name='Register as Astrologer' component={AstrologerRegistration} options={{
title:" Register as Astrologer",
drawerIcon:({ color, size }) => (<FontAwesome name="user" size={20} color={color} />)
}}/>
<Drawer.Screen name='Settings' component={Settings} options={{
drawerIcon:({ color, size }) => (<Ionicons name="settings-sharp" size={20} color={color} />)
}}/>
<Drawer.Screen name='Share' component={Share} options={{
drawerIcon:({ color, size }) => (<Ionicons name="share-social" size={20} color={color} />)
}}/>
<Drawer.Screen name='Rate Us' component={RateUs} options={{
drawerIcon:({ color, size }) => (<Feather name="star" size={20} color={color} />)
}}/>
</Drawer.Navigator>
)
}
export default function Navigation() {
const [isAuthorized, setIsAuthorized] = useState(false);
const [country,setCountry]=useState(null);
useEffect(()=>{
AsyncStorage.getItem('persist:root').then((data) => {
if (data) {
const persistedState = JSON.parse(JSON.parse(data).auth);
setIsAuthorized(persistedState.isAuthenticated);
}
});
const fetchCountry=async()=>{
const request = await fetch("https://ipinfo.io/json?token=6cae93b1bf8907")
const jsonResponse = await request.json()
console.log(jsonResponse.ip, jsonResponse.country)
setCountry(jsonResponse.country)
}
fetchCountry();
},[]);
useEffect(() => {
console.log("Country ",country); // Log the country name whenever it changes
}, [country]);
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{
headerShown:false
}}>
{country === 'IN' ? (
<Stack.Screen name='Phone Login' component={LogInviaPhone} />
) : (
<Stack.Screen name='Email Login' component={LogInviaEmail} />
)}
<Stack.Screen name='OTP Phone' component={OTPScreen} />
<Stack.Screen name='Main Drawer' component={MainDrawer} />
<Stack.Screen name='OTP Email' component={OTPScreenEmail} />
<Stack.Screen name='Home Screen' component={MainTab} />
<Stack.Screen name='User Details' component={UserDetails} options={{
headerShown:true,
title:"Profile"
}}/>
<Stack.Screen name='Header' component={AppHeader}/>
</Stack.Navigator>
</NavigationContainer>
)
}
What should I do I tried navigation prop and useNavigation both It was working earlier but suddenly started showing this error also I have to apply a condition here that if user has authorized then he should directly navigate to home screen but because of this navigation issue it is not working and I had to delete it.
As mentioned in docs, this does not work.
Note that you cannot use the useNavigation hook inside the drawerContent since useNavigation is only available inside screens. You get a navigation prop for your drawerContent which you can use instead:
I have created an example for my solution approach.
import * as React from 'react';
import { forwardRef, useRef } from 'react';
import { View, Text, Button, Pressable } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '@react-navigation/drawer';
function Feed({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Feed Screen</Text>
<Button
title="Open drawer"
onPress={() => {
navigation.openDrawer();
}}
/>
<Button
title="Toggle drawer"
onPress={() => {
navigation.toggleDrawer();
}}
/>
</View>
);
}
function Notifications() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Notifications Screen</Text>
</View>
);
}
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
label="Close drawer"
onPress={() => props.navigation.closeDrawer()}
/>
<DrawerItem
label="Toggle drawer"
onPress={() => props.navigation.toggleDrawer()}
/>
</DrawerContentScrollView>
);
}
const Drawer = createDrawerNavigator();
// Add the forwardRef
const MyDrawer = forwardRef(function MyDrawer(_props, ref) {
return (
<Drawer.Navigator
drawerContent={(props) => {
ref.current = props.navigation; // Set the ref with your Drawer reference
return <CustomDrawerContent {...props} />;
}}>
<Drawer.Screen name="Feed" component={Feed} />
<Drawer.Screen name="Notifications" component={Notifications} />
</Drawer.Navigator>
);
});
export default function App() {
const drawerNavRef = useRef();
return (
<NavigationContainer>
<View
style={{ height: 250, justifyContent: 'center', alignSelf: 'center' }}>
<Pressable
onPress={() => {
drawerNavRef.current.toggleDrawer(); // Access your drawer outside from Drawer.Navigator
}}>
<Text>Header Toggle</Text>
</Pressable>
</View>
<MyDrawer ref={drawerNavRef} />
</NavigationContainer>
);
}