Getting undefined is not an object (evaluating '_this.props.navigation') - react-native

I'm using DrawerNavigator and I have 3 pages: Router page, mainScreen and a photos page.
I maked a header navbar area and I used This <TouchableHighlight onPress={() => this.props.navigation.navigate('DrawerOpen')}> to open Drawer menu in mainScreen and used that for photos page too, menu is ok in mainScreen but when I click <TouchableHighlight onPress={() => this.props.navigation.navigate('DrawerOpen')}> in photos page, I get the error:
undefined is not an object (evaluating '_this.props.navigation')
How can I fix that?
My photos page:
import React from 'react';
import { Button, ScrollView, View, Text, StyleSheet, TouchableHighlight } from 'react-native';
import { DrawerNavigator } from 'react-navigation';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import Icon from 'react-native-vector-icons/FontAwesome'
const MyNavScreen = ({ navigation }) => (
<View>
<View style={styles.containerNavbar}>
<TouchableHighlight onPress={() => this.props.navigation.navigate('DrawerOpen')}>
<Icon name="bars" size={30} color="#fff" />
</TouchableHighlight>
<Text style={styles.navbarTitle}>Photos</Text>
</View>
<ScrollView>
<View><Text>photo</Text></View>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</ScrollView>
</View>
);
const MyPhotosHomeScreen = ({ navigation }) => (
<MyNavScreen navigation={navigation} />
);
MyPhotosHomeScreen.navigationOptions = {
title: 'Photos',
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="photo"
size={24}
style={{ color: tintColor }}
/>
),
};
export default MyPhotosHomeScreen;
mainScreen:
export default class MainScreen extends React.Component {
static navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="home"
size={24}
style={{ color: tintColor }}
/>
)
};
render() {
return (
<View>
<View style={styles.containerNavbar}>
<TouchableHighlight onPress={() => this.props.navigation.navigate('DrawerOpen')}>
<Icon name="bars" size={30} color="#fff" />
</TouchableHighlight>
<Text style={styles.navbarTitle}>mainScreen</Text>
</View>
<View>
<View style={styles.containerFooter}>
<Text style={styles.footerTitle}>Footer</Text>
</View>
</View>
</View>
)
}
}

If you are using navigation in child component don't forget to send navigation in props to child
<ChildComponent navigation={this.props.navigation}/>
Access in child component like this
props.navigation.navigate("ScreenName")

Perhaps I'm overlooking something, but it just looks like a simple Javascript error. You're destructing your props in your pure component MyNavScreen:
const MyNavScreen = ({ navigation }) => (
This means that you don't have access to this.props. You just have access to the destructured prop navigation. Hence the reason for the undefined error as this really is undefined:
<TouchableHighlight onPress={() => this.props.navigation.navigate('DrawerOpen')}>
If you change it instead to use navigation directly, it should work:
<TouchableHighlight onPress={() => navigation.navigate('DrawerOpen')}>
On mainScreen, you are fine because it's not a pure component with destructured arguments. So you still have access to this.props in render().
You should brush up on destructing if this is causing you trouble.

Binding this worked for me
In my case it worked when I bind this to the method that calls the prop it in the constructor.
constructor(props){
super(props);
this.showDetails = this.showDetails.bind(this);// you should bind this to the method that call the props
}
showDetails(_id){
this.props.navigation.navigate('Details');
}
for functional components try useNavigation hook for deep navigation
Or Simply use arrow function
showDetails = (_id) => {
this.props.navigation.navigate('Details');
}
because while you use expression function it is going to create it's own scope.

Try this:
import { withNavigation } from 'react-navigation';
withNavigation serves the props all over the project/app, you access the navigation props from anywhere.
and
onPress={() => this.props.navigation.navigate('DrawerOpen')}
Finally,
export default withNavigation(MyPhotosHomeScreen);
check out this https://reactnavigation.org/docs/en/connecting-navigation-prop.html

If you use TouchableOpacity/Height in your child element, pass it this.props.onPress like this:
<TouchableOpacity onPress={this.props.onPress}/>
Then call the onPress function in your parent component like this:
<Parent onPress={this.Handlepress} />

very simple: follow some steps here
import {useNavigation} from '#react-navigation/native';
const Home =()=>{
//add this line under function scope.
const navigation = useNavigation();
return(
<TouchableOpacity onPress={() => navigation.navigate('Detail')}>
//your code.......................
)
}

This is how I have done it in React Navigation 2 release: I call the openDrawer() method from a StackNavigator that is a child navigator of the DrawerNavigator.
This is my DrawerNavigator:
export const Drawer = DrawerNavigator(
{
MyAccount: {screen: TabsStack},
});
export const TabsStack = StackNavigator({
Tabs: {
screen: Tabs, navigationOptions: ({navigation}) => ({
headerLeft: (
<TouchableOpacity style={{marginLeft: 10, marginTop: 3}}
onPress={() => navigation.openDrawer()}>
<Image source={require('./assets/menu_h.png')}/>
</TouchableOpacity>)
})

functional components take props as argument.
You should try this
const MyNavScreen = ({props}) =>
and then call the props without this key word
onPress = {() => props.navigation.navigate('DrawerOpen')}

If you want navigation in child component,then you have to get props in child component.
Suppose you have 3 components - Comp_1,Comp_2,Comp_3 and you want to navigate from Comp_2 -> Comp_3. To do this follow these steps.
Pass props in Comp_1 component.Like this
<Comp_2 navigation={this.props.navigation}/>
Now in Comp_2, we can navigate from Comp_2 -> Comp_3 like this.
this.props.navigation.navigate('Comp_3');
For example -
<Button
onPress = {() => this.props.navigation.navigate('Comp_3')}
title = 'Go to Comp_3 Screen'
/>

In then compnent that you're trying enter to another view you must send the object navigation by you use this in the onPress of component imported
example
Implementing component in a view
<CardComponent title="bla bla" navigation={this.props.navigation} />
Component template
<View>
<Button title={this.props.title} onPress={()=>
this.props.navigation.navigate("anotherAwesomeView")}/>
</View>
This problem is because the component that you're trying implement is not defined on stackNavigation, and by this the methot navigation is not avalible for you, and passing this object navigator by params you'll can access to it

For those who are not using class components and prefer functional components:
First import useNavigation then from the screen that you wish to navigate from, initiate (declare) the variable navigation = useNavigation();
import { useNavigation } from '#react-navigation/native';
function ScreenToNavigateFrom() {
const navigation = useNavigation();
return(
<TouchableOpacity onPress={() => navigation.navigate('AnotherScreen')}>
<Text style={{fontWeight: "bold", color:"white" }} >Performance</Text>
</TouchableOpacity>
);
}
This answer is courtesy of this gisthub issue: https://github.com/react-navigation/react-navigation/issues/7961

i had the same problem when i was using the header component
now you can use the navigation variable in other component like this
<TouchableOpacity onPress={() => { this.props.navigation.navigate("Play");}}>
Happy Codding :)

try this instead you might be missing to import useNavigation() from '#react-navigation/native';
import { useNavigation } from '#react-navigation/native';
function NotificationsScreen() {
const navigation = useNavigation();
return(
<Button
onPress={() => navigation.navigate('Notifications')}
title="Go to notifications"
/>
);
}
enter code here

I encountered the same problem. That's how I solved it:
Verify that all your constructors have "props" has argument
Bind the function with use the function this.props.navigation.navigate in the constructor like this: this.your_function = this.your_function.bind(this)

when you defined screen in createStackNavigator , it by default pass a props called navigation,
something like this => navigation={this.props.navigation}
but when you using this.props.navigation.navigator("YOUR SCREEN ")
and didn't defined this screen at createStackNavigator you must pass the navigation={this.props.navigation} form the screen that you defined in createStackNavigator and then you can use it in your component .

class ProductScreen extends Component {
export default ProductScreen; // make sure bottom this line mention
Call this
<TouchableOpacity
onPress = {() => this.props.navigation.navigate('ProductAddScreen')}
activeOpacity={0.7} style={styles.button}>
<Text style={styles.message}>{this.state.notFound} </Text>
</TouchableOpacity>

Related

Repeatedly popping "undefined is not an object (evaluating 'navigation.navigate')" after routing a particular screen

const ResolvedPlaces = ({navigation}) => {
return(
<View style={Styles.headerWrapper}>
<TouchableOpacity navigation={navigation} onPress={()=> navigation.navigate("ProfileScreen")} >
<Text style={[Styles.header,{fontWeight:"bold"}]}>Resolved </Text>
<Text style={Styles.header}> places</Text>
</TouchableOpacity>
</View>
)
}
I have created a ResolvedPlaces function and gave a option to route to the profile screen. Also I've destructured the "navigation" in all format. But I continuously got this navgation.navigate as undefined object.
the error message on the terminal
If ResolvedPlaces is not defined as a Screen in a react-native-navigation navigator, then the navigation prop will not be passed automatically to the component ResolvedPlaces.
If ResolvedPlaces is nested inside a Screen that is defined in a Navigator, then you can use the navigation prop directly. This could look as follows.
const SomeScreen = ({navigation}) => {
const ResolvedPlaces = () => {
return(
<View style={Styles.headerWrapper}>
<TouchableOpacity onPress={()=> navigation.navigate("ProfileScreen")} >
<Text style={[Styles.header,{fontWeight:"bold"}]}>Resolved </Text>
<Text style={Styles.header}> places</Text>
</TouchableOpacity>
</View>
)
}
return (
<ResolvedPlaces />
)
}
The component SomeScreen must be defined in a navigator, e.g. a Stack.
If ResolvedPlaces is a component defined in its own file, then pass the navigation object as a prop from the parent that is defined as a screen.
const SomeScreen = ({navigation}) => {
return <ResolvedPlaces navigation={navigation} />
}
If this is not an option than you can still use the useNavigation hook as follows.
const ResolvedPlaces = () => {
const navigation = useNavigation()
return (
<View style={Styles.headerWrapper}>
<TouchableOpacity onPress={()=> navigation.navigate("ProfileScreen")} >
<Text style={[Styles.header,{fontWeight:"bold"}]}>Resolved </Text>
<Text style={Styles.header}> places</Text>
</TouchableOpacity>
</View>
)
}
Remarks: I have removed the navigation prop from the TouchableOpacity since this prop does not exist for this component. The basic react-native-navigation structure is documented here.

How To Call Our Own Build withNavigation In React Native 6

Help,
Firstly, did React Native 6 or 5 have withNavigation ? I cannot find it in the documentation in React Native website.
So, I found some thread that we can build our own withNavigation like this :
withNavigation.js
import React from 'react';
import { useNavigation } from '#react-navigation/native'; // not sure package name
export const withNavigation = (Component) => {
return (props) => {
const navigation = useNavigation();
return <Component navigation={navigation} {...props} />;
};
};
But I don't know how to call or use the own build withNavigation.
This is my source code :
ResultList.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { FlatList, TouchableOpacity } from 'react-native-gesture-handler';
import ResultsDetail from './ResultsDetail';
import { withNavigation } from '../helper/withNavigation';
const ResultList = ({ title, results }) => {
console.log(withNavigation.component);
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<FlatList
horizontal={true}
showsHorizontalScrollIndicator={false}
data={results}
keyExtractor={(results) => results.id}
renderItem={({item}) => {
return (
<TouchableOpacity onPress={() => withNavigation('ResultShowScreen')}>
<ResultsDetail results={item} />
</TouchableOpacity>
)
}}
/>
</View>
)
};
const styles = StyleSheet.create({
title: {
fontSize: 18,
fontWeight: 'bold',
marginLeft: 15,
marginBottom: 5,
},
container: {
marginBottom: 10
}
});
export default ResultList;
In here :
console.log(withNavigation.component)
it show : undefined
How to get the navigation props with our own withNavigation ?
Thank You
Since your helper function, withNavigation, is a Higher-Order Component (HoC) you have to wrap your component with it in order to be able to use it:
const ResultList = ({ title, results, navigation }) => {
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<FlatList
horizontal={true}
showsHorizontalScrollIndicator={false}
data={results}
keyExtractor={(results) => results.id}
renderItem={({ item }) => {
return (
// Now you can use the navigation prop inside of your component
<TouchableOpacity onPress={() => navigation.navigate('MyRoute')}>
<ResultsDetail results={item} />
</TouchableOpacity>
);
}}
/>
</View>
);
};
// withNavigation adds the navigation property to your ResultList component's properties
export default withNavigation(ResultList);
I think the reason why you can't find withNavigation inside of React Navigation 5 or 6 anymore is because they suggest you to use their built-in hooks instead. I am not sure why do you need to use a custom made HoC when you could just use the useNavigation hook. If you don't have a specific reason to use your custom HoC, the built-in hooks could simplify your code:
import { useNavigation } from '#react-navigation/native';
const ResultList = ({ title, results }) => {
const navigation = useNavigation();
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<FlatList
horizontal={true}
showsHorizontalScrollIndicator={false}
data={results}
keyExtractor={(results) => results.id}
renderItem={({ item }) => {
return (
// You can use the navigation property inside of your component
<TouchableOpacity onPress={() => navigation.navigate('MyRoute')}>
<ResultsDetail results={item} />
</TouchableOpacity>
);
}}
/>
</View>
);
};
export default ResultList;
As per the upgrading documentation here
React Navigation 4.x included higher order components such as
withNavigation and withNavigationFocus. Now they live in the compat
package.
The documentation says that in order to upgrade from React Navigation 4 to 5:
withNavigation HOC is moved to another package #react-navigation/compat
So, in order to use that you have to import that package first:
import { withNavigation } from '#react-navigation/compat';

React Native getting navigation prop in a regular object

I have a navigation component where my screens are give a header component
<Stack.Screen
name="AddNewHabitScreen"
component={AddNewHabitScreen}
options={{ ...HeaderBar, title: "New Habits" }}
/>
The HeaderBar is just a simple object with option configurations
const HeaderBar = {
...
headerRight: () => (
<TouchableOpacity onPress={navigate(route)}>
<Image
source={require('../../assets/icons/B_icon_header_info.png')}
/>
</TouchableOpacity>
),
Since it's not a class or functional component I'm not sure how to use hooks or props to give the route information so it can navigate correctly. How would I go about doing this?
Something like
const HeaderBar = ({navigation}) {
...
headerRight: (navigation) => (
<TouchableOpacity onPress={navigation.navigate(route)}>
<Image
source={require('../../assets/icons/B_icon_header_info.png')}
/>
</TouchableOpacity>
),

How to access navigation outside main component?

I've been working with the default tabs project created with create-react-native-app.
So I created my own screen where this.props.navigation is accessible in the main (export default class) component. It works fine to do navigate('Search') from the button titled 'nav default'.
However, after many tries, I couldn't navigate from either the button in the headerRight or in my custom component MyComponent.
How do I change my alerts to instead do navigate('Search') like the main component?
import React from 'react';
import { Button, Dimensions, ScrollView, StyleSheet, Text, View } from 'react-native';
class MyComponent extends React.Component {
// i wish i could navigate from here
render() {
//const { navigate } = this.props.navigation; // this causes TypeError undefined is not an object (evaluating this.props.navigation.navigate)
return (
<View>
<Button title="nav from component" onPress={() => alert('This should navigate, not alert')} color="red" />
</View>
);
}
}
export default class MyScreen extends React.Component {
// i wish i could navigate from here too
static navigationOptions = {
title: 'Test',
headerRight: (
//<Button onPress={() =>navigate('Search')} /> // how do I achieve this?
<Button title="nav from header" onPress={() => alert('This should navigate, not alert')} />
),
};
render() {
const { navigate } = this.props.navigation;
return (
<ScrollView style={styles.container}>
<Button onPress={() =>navigate('Search')} title="nav default" />
<MyComponent />
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 15,
backgroundColor: '#fff',
},
});
There are two different problems. First, navigation is only passed as a prop to the components that are navigation screens. So, to access it from other components, such as your MyComponent, you have to pass it through props <MyComponent navigation={navigation} /> and then you can use this.props.navigation.navigate inside it. You can also use the withNavigation higher order component, but in that case the first approach is better.
The other problem is, if you want to access the navigation prop in navigationOptions, you should define it as a function, and not as an object. The implementation would be something like this:
static navigationOptions = ({ navigation }) => ({
title: 'Test',
headerRight: (
<Button onPress={() =>navigation.navigate('Search')} />
),
});

The side menu button in navigation drawer is not working when i press it in React native

static navigationOptions = ({navigation}) => {
return {
headerLeft: (
<View style ={{padding:10}}>
<Ionicons name = "md-menu" size={32} onPress ={()=>{navigation.navigate('DrawerOpen')}}/>
</View>
)
}
}
As by React Navigation(v2). you may find the documentation here https://reactnavigation.org/docs/en/drawer-based-navigation.html
you need to use like this below
static navigationOptions = ({ navigation }) => ({
headerLeft: <Button onPress={() => navigation.toggleDrawer()} />
})
To open and close drawer, use the following helpers to open and close the drawer:
this.props.navigation.openDrawer();
this.props.navigation.closeDrawer();
If you would like to toggle the drawer you call the following:
this.props.navigation.toggleDrawer();
Each of these functions, behind the scenes, are simply dispatching actions:
this.props.navigation.dispatch(DrawerActions.openDrawer());
this.props.navigation.dispatch(DrawerActions.closeDrawer());
this.props.navigation.dispatch(DrawerActions.toggleDrawer());
This solved the issue of navigation for me.
Install NativeBase by running npm install --save native-base
Run react-native link to link the fonts
Import this import {Header, Left, Icon} from 'native-base'
The add this code to render(){}
render() {
return (
<View>
<Header>
<Left>
<Icon name="menu" style={{ color: 'white'}}
onPress={() => this.props.navigation.toggleDrawer()} />
</Left>
</Header>
<View>
<Text>Home Contents</Text>
</View>
</View>
);
}