48

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')

Photo

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>

        )
    }
}
Ted Klein Bergman
  • 9,146
  • 4
  • 29
  • 50
Saeed Heidarizarei
  • 8,406
  • 21
  • 60
  • 103
  • Well I think it is evident you are not including everything in the photos page. Please update your code with all of the code from both files so we can see what is missing. – wuno Jul 20 '17 at 23:16
  • 1
    This is my all code without my style, i passed my photos page from ` ` , and I can see photo text and back button in photo page, but i should add my router page if you need? – Saeed Heidarizarei Jul 20 '17 at 23:32
  • I'm also encounter the same issue i ```import { useNavigation } from '@react-navigation/native';``` const navigation = useNavigation(); this help me. – vibhu May 10 '21 at 06:52

16 Answers16

43

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")
Sumedh Ulhe
  • 667
  • 5
  • 10
  • 4
    perfect solution! saved my day:) – Bikram Nath Jun 02 '20 at 09:28
  • 1
    **If navigation is not working for you at all** - All these assume that in your `App()` you have `` (yes just the navigation component, not the "Home" "Main" or anything like that) - where `YourNavigatorComponent` is the thing returning`...` where you link the "Home"/"Main" components/screens and other, just putting it out there, since I thought this was more automatic, it isn't. – jave.web Jun 17 '21 at 05:55
  • 1
    Correct Solution Thank you. – vaibhav gadekar Sep 14 '21 at 12:07
  • 1
    stackoverflow saves the day.. :D – Sudharsan Palanisamy Jan 21 '22 at 08:41
  • Suppose, you have screen A, wich shows component B, wich shows component C. I want to go back from C to B. Do I have to insert the navigation from screen A? Or can I start from B? – Yannick Mussche Jan 20 '23 at 08:50
27

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.

Michael Cheng
  • 9,644
  • 6
  • 46
  • 48
  • Thank you Dear @michael-cheng, Solved.and whitch way is better? my code is okey? and can i continue? or I should change to reder() mode and add this.props? – Saeed Heidarizarei Jul 21 '17 at 02:07
  • @SedricHeidarizarei I'm of the opinion that with **destructuring**, there is no "better way". It's simply a tool to help make code more readable. Whether or not you use it depends on your style and your team's style. This is *my opinion* though and I'm certainly not an expert on Javascript so take my word with a grain of salt. – Michael Cheng Jul 21 '17 at 02:39
  • 1
    @SedricHeidarizarei As for **pure components**, there are good reasons to use them. There are quite a few articles online about when and how to best use them. I recommend taking a bit of time to read up on them as it'll give you a better understanding of both React and how to architect your code. There's even [a question on StackOverflow covering this topic](https://stackoverflow.com/questions/40703675/react-functional-stateless-component-purecomponent-component-what-are-the-dif) that goes into more nuances. For example, your `photos page` specifically is a **functional stateless component**. – Michael Cheng Jul 21 '17 at 02:43
  • thanks this solution worked. previously I got stuck on this as I was using non-render method to use the navigation props. – amit pandya Jan 29 '20 at 08:19
20

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.


Rohit Chahal
  • 53
  • 1
  • 6
bereket gebredingle
  • 12,064
  • 3
  • 36
  • 47
13

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

ochs.tobi
  • 3,214
  • 7
  • 31
  • 52
sai teja
  • 138
  • 1
  • 6
8

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} />
Kevin Kiwango
  • 111
  • 1
  • 4
4

very simple: follow some steps here

  1. import {useNavigation} from '@react-navigation/native';

  2. const Home =()=>{

//add this line under function scope.

const navigation = useNavigation();

return(

<TouchableOpacity onPress={() => navigation.navigate('Detail')}>

//your code.......................

)

}

sherkhan
  • 811
  • 8
  • 8
2

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>)
        })
sɐunıɔןɐqɐp
  • 3,332
  • 15
  • 36
  • 40
2

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')} 
Nikolai Shevchenko
  • 7,083
  • 8
  • 33
  • 42
B. Mohammad
  • 2,152
  • 1
  • 13
  • 28
2

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.

  1. Pass props in Comp_1 component.Like this

    <Comp_2 navigation={this.props.navigation}/>

  2. 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' />

Jitender Sharma
  • 141
  • 1
  • 5
2

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

Desarrollalab
  • 337
  • 2
  • 5
2

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

AnatuGreen
  • 579
  • 7
  • 14
1

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 :)

MedElmaachi
  • 916
  • 7
  • 7
1

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
Ch.M Emran
  • 11
  • 1
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 22 '21 at 07:14
0

I encountered the same problem. That's how I solved it:

  1. Verify that all your constructors have "props" has argument
  2. Bind the function with use the function this.props.navigation.navigate in the constructor like this: this.your_function = this.your_function.bind(this)
Partho63
  • 3,117
  • 2
  • 21
  • 39
0

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 .

Ali Dehghan
  • 1
  • 1
  • 1
0

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>
Keshav Gera
  • 10,807
  • 1
  • 75
  • 53