How to solve navigation.navigate error when set TouchableOpacity in StackScreen header options? - react-native

I want to add a button(icon) on stack header(on right side). On-click it goes to that page but it's not working. It appears 'undefined is not an object (evaluating 'navigation.navigate')'.
Below is my code:
<Stack.Navigator>
<Stack.Screen name="Page1" component={Page1} />
<Stack.Screen
name="Page2"
component={Page2}
options={{
headerRight: () => (
<View>
<TouchableOpacity
onPress={() => navigation.navigate('Page3')}>
<Image source={require('../assets/image.png')} />
</TouchableOpacity>
</View>
)
}}
/>
<Stack.Screen name="Page4" component={Page4} />
<Stack.Screen name="Page5" component={Page5} />
</Stack.Navigator>

You can pass the navigation from the options to the headerRight:
options={({navigation}) => ({
headerRight: () => (
...
),
})}
or useNavigation():
const navigation = useNavigation();
EDIT 2:
fixed your snack code and its working fine:
You had to add a stackScreen called 'MyorderStack' because you're trying to navigate to that.
<NavigationContainer independent={true}>
<Stack.Navigator screenOptions={{ headerTintColor: 'blue' }}>
<Stack.Screen name="Global Page" component={AppNavigator} options={{ headerShown: false }} />
<Stack.Screen name="DetailOne" component={DetailOne} options={({navigation}) => ({ headerBackTitleVisible: false, title: 'Global Page',
headerRight: () => (
<View style={{flexDirection: 'row',justifyContent: 'flex-end',width: '50%'}}>
<View style={{ marginRight: 10 }}>
<TouchableOpacity onPress={() => navigation.navigate('MyorderStack')}>
<Image source={require('./assets/shop.png')} style={styles.Image} />
</TouchableOpacity>
</View>
</View>
), headerTitleAlign:'center', headerTintColor:colors.primary
})}
/>
<Stack.Screen name="DetailTwo" component={DetailTwo} options={{headerBackTitleVisible: false, headerTitleAlign: 'center', title: 'Global Page', headerTintColor: colors.primary}} />
<Stack.Screen name="MyorderStack" component={MyorderStack} options={{headerBackTitleVisible: false, headerTitleAlign: 'center', title: 'Global Page', headerTintColor: colors.primary}} />
</Stack.Navigator>
</NavigationContainer>

Navigation is only defined within the screen's components. In your case, you can try useNavigation hook to navigate to different screen. Import it like:
import { useNavigation } from '#react-navigation/native';
and declare it like:
const navigation = useNavigation();
Then you it to your TouchableOpacity prop like onPress={() => navigation.navigate('Page3')}.
Hope this works for you. Thanks

Related

How to inject NativeID to React Navigation material-top-tabs?

I am using #react-navigation/material-top-tabs to display tabs in my application. How can I inject NativeID to tabs to have an access to them with e.g. Selenium?
The only way that I found was using tabBar property, creating custom tabs and adding NativeID to TouchableOpacity. Is there more simple way?
<NavigationContainer>
<Tab.Navigator tabBar={(props) => <MyTabBar {...props} />} >
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
</NavigationContainer>
function MyTabBar({ state, descriptors, navigation, position }) {
return (
<View style={{ flexDirection: 'row', paddingTop: 20 }}>
{
state.routes.map((route, index) => {
// ....
return (
<TouchableOpacity nativeID={"tab_"+label} >
<Animated.Text style={{ opacity }}>{label}</Animated.Text>
</TouchableOpacity>
);
})}
</View>
);
}

Stack navigator header button doesn't navigate to route on press

Here is my error: undefined is not an object (evaluating 'navigation.navigate')
My goal is to navigate to my Settings page when on click on my LeftHeader component in my StackNavigator:
Here is a snippet of my App.js file:
const FeedStackNav = () => {
return (
<Stack.Navigator>
<Stack.Screen
options={{
title: "",
headerLeft: ({ navigation }) => (
<Header>
<LeftHeader onPress={() => navigation.navigate("Settings")}>
<MenuIcon fill={"#C13B1E"} />
</LeftHeader>
</Header>
),
}}
name="Feed"
component={Feed}
/>
</Stack.Navigator>
);
};
And here is how I am rendering the Stack in my app:
<NavigationContainer theme={theme}>
<Stack.Navigator>
<Stack.Screen
options={{
headerShown: false,
}}
name=" "
component={TabNav}
/>
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
</NavigationContainer>
There has to be something wrong with my LeftHeader onPress function
Am adding just snippet of code to illustrate how to use navigation.navigate('screen') on header button
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}>
<Stack.Screen
name="Home"
component={HomeScreen}
options={({navigation, route}) => ({
headerRight: () => (
<TouchableOpacity onPress={() => alert('Just clicked!!')}>
<FontIcon
onPress={() => navigation.navigate('CreateSession')}
name="video-camera"
color={whitish}
size={25}
/>
</TouchableOpacity>
),
})}
/>
<Stack.Screen name="CreateSession" component={CreateSessionScreen} />
<Stack.Screen name="LiveSessions" component={LiveSession} />
</Stack.Navigator>
</NavigationContainer>
on above code observe the callback function used to get access to navigation and route props
options={({navigation, route}) => ({
headerRight: () => (
<TouchableOpacity onPress={() => alert('Just clicked!!')}>
<FontIcon
onPress={() => navigation.navigate('CreateSession')}
name="video-camera"
color={whitish}
size={25}
/>
</TouchableOpacity>
),
})}

Customize header in react native navigation

in my app home screen I want to custom the header to have two icons in left and right which can be done using:
<HomeStack.Screen
name="Home"
component={HomeScreen}
options={{
title: '',
headerLeft: () => (
<View style={{ marginLeft: 10 }}>
<Icon.Button
name="ios-menu"
size={25}
color="#000000"
backgroundColor={COLORS.primary}
onPress={() => navigation.openDrawer()}
/>
</View>
),
headerRight: () => (
<View style={{ marginLeft: 10 }}>
<Icon.Button
name="location-outline"
size={25}
color="#000000"
backgroundColor={COLORS.primary}
onPress={() => navigation.openMap()}
/>
</View>
),
}} />
</HomeStack.Navigator>
I want to add additional but to be in the center which will be customized based on my needs, but I have no idea how to implement that as there is nothing called headerCneter:
Perhaps you can take advantage of the header option inside the stack navigator? You can then use the route params to customize your header from there.
You can pass react component in headerTitle:
<HomeStack.Screen
name="Home"
component={HomeScreen}
options={{
headerTitle: () => {
return (
<View style={st.horizontalRow}>
<LeftIcon />
<TextInput
placeholder="search"
/>
<RightIcon />
</View>
);
},
headerTitleAlign: 'left',
headerTitleContainerStyle: {
left: 40,
right: 0,
},
}} />

React navigation v5, add a stack navigation to my application header

I'm using react navigation 5 to build my app navigation system.
I want to add a link to open Notifications scree:
I created a RenderHeaderRight component to override the right component of all my stacks
navigation :
const RenderHeaderRight = ({navigation}) => {
return (
<View style={{flexDirection: 'row-reverse'}}>
<TouchableHighlight
underlayColor={COLORS.DEFAULT}
style={styles.iConMenuContainer}
onPress={() => navigation.openDrawer()}>
<Image source={menu} style={styles.iConMenu} />
</TouchableHighlight>
<TouchableHighlight
underlayColor={COLORS.DEFAULT}
style={styles.notificationsIconContainer}
onPress={() => navigation.navigate('Notifications')}>
<>
<Image source={notifications} style={styles.notificationsIcon} />
<Image source={notifMark} style={styles.badge} />
</>
</TouchableHighlight>
</View>
);
};
In my HomeStackScreen i'm using the RenderHeaderRight :
const HomeStackScreen = ({navigation}) => (
<HomeStack.Navigator
initialRouteName="Home"
headerMode="screen"
mode="modal"
screenOptions={{
headerStyle: {
backgroundColor: COLORS.WHITE,
elevation: 0, // remove shadow on Android
shadowOpacity: 0, // remove shadow on iOS
borderBottomWidth: 0,
},
headerTintColor: COLORS.GREY,
headerTitleStyle: {
fontFamily: 'Montserrat-SemiBold',
fontWeight: '600',
fontSize: 18,
},
}}>
<HomeStack.Screen
name="Home"
component={Home}
options={{
title: 'Expanded',
headerLeft: () => <RenderHeaderLeft />,
headerRight: () => <RenderHeaderRight navigation={navigation} />,
headerTitleAlign: 'left',
}}
/>
<HomeStack.Screen name="HomeDetails" component={HomeDetails} />
</HomeStack.Navigator>
);
When i click on the Header right button to open the Notifications screen i got an error :
The action 'NAVIGATE' with payload {"name":"Notifications"} was not handled by any navigator.
Where shoud i create the stack navigation of Notifications screen ?
I triend to add the notifications like this :
const HomeStackScreen = ({navigation}) => (
<HomeStack.Navigator
initialRouteName="Home"
headerMode="screen"
mode="modal"
screenOptions={{
headerStyle: {
backgroundColor: COLORS.WHITE,
elevation: 0, // remove shadow on Android
shadowOpacity: 0, // remove shadow on iOS
borderBottomWidth: 0,
},
headerTintColor: COLORS.GREY,
headerTitleStyle: {
fontFamily: 'Montserrat-SemiBold',
fontWeight: '600',
fontSize: 18,
},
}}>
<HomeStack.Screen
name="Home"
component={Home}
options={{
title: 'Expanded',
headerLeft: () => <RenderHeaderLeft />,
headerRight: () => <RenderHeaderRight navigation={navigation} />,
headerTitleAlign: 'left',
}}
/>
<HomeStack.Screen name="HomeDetails" component={HomeDetails} />
<HomeStack.Screen
name="Notifications". // add the screen here
component={Notifications}
options={{headerShown: false}}
/>
</HomeStack.Navigator>
);
Removed the unnecessary styling / images
From my understanding you need to have a root Drawer.Navigator and from inside your Home screen, you need a Stack.Navigator there
This article explains the details of combining react-native-navigators
import React from "react"
import { TouchableHighlight, View, Text } from "react-native"
import { NavigationContainer } from "#react-navigation/native"
import { createDrawerNavigator } from "#react-navigation/drawer"
import { createStackNavigator } from "#react-navigation/stack"
const RenderHeaderRight = ({ navigation }) => {
return (
<View style={{ flexDirection: "row-reverse" }}>
<TouchableHighlight onPress={() => navigation.openDrawer()}>
<View>
<Text>Menu</Text>
</View>
</TouchableHighlight>
<TouchableHighlight onPress={() => navigation.navigate("Notifications")}>
<>
<View>
<Text>Image 1</Text>
</View>
<View>
<Text>Image 2</Text>
</View>
</>
</TouchableHighlight>
</View>
)
}
const Stack = createStackNavigator()
const Drawer = createDrawerNavigator()
const Notifications = () => (
<View>
<Text>Notifications</Text>
</View>
)
const Home = () => (
<View>
<Text>Home</Text>
</View>
)
const NotificationsScreen = () => (
<View>
<Text>Notifications Screen</Text>
</View>
)
const HomeScreen = () => (
<View>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={({ navigation }) => ({
title: "Home",
headerRight: () => <RenderHeaderRight navigation={navigation} />,
})}
navigationOptions={({ navigation }) => ({
headerTitleAlign: "left",
})}
/>
<Stack.Screen name="Notifications" component={Notifications} />
</Stack.Navigator>
</View>
)
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>
</NavigationContainer>
)
}

react navigation 5 header is not shown

Using react navigation 5, I want to create a dynamic map for all my Drawer Screens, but the header is not shown with code:
<NavigationContainer>
<Drawer.Navigator
drawerContent={props => <DrawerContent {...props} />}>
{stackNavigItens.map((props, r) => (
<Drawer.Screen
key={r.name}
name={r.name}
component={({navigation}) => (
<Stack.Navigator
initialRouteName="Home"
headerMode="screen"
screenOptions={{
headerTitle: r.label,
headerStyle: {
backgroundColor: '#2e72e8',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}
{...props}>
<Stack.Screen
name={r.name}
component={r.component}
options={{
title: r.label,
headerLeft: () => (
<Icon.Button
name="ios-menu"
size={25}
backgroundColor="#2e72e8"
onPress={() => {
navigation.openDrawer();
}}
/>
),
}}
{...props}
/>
</Stack.Navigator>
)}
{...props}
/>
))}
</Drawer.Navigator>
</NavigationContainer>
If I use every createStackNavigator in a const like below, and then call inside component of the Drawer the header shows correctly, I don't know Why ? I think maybe because of the {navigation} arrow function, but don't work too.
const HomeStackScreen = ({navigation}) => (
<HomeStack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#2e72e8',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}>
<HomeStack.Screen
name="Home"
component={HomeScreen}
options={{
headerLeft: () => (
<Icon.Button
name="ios-menu"
size={25}
backgroundColor="#2e72e8"
onPress={() => {
navigation.openDrawer();
}}
/>
),
}}
/>
</HomeStack.Navigator> );