React Native - navigation issue "undefined is not an object (this.props.navigation.navigate)"

74,329

Solution 1

With Expo you should't do the App registration your self instead you should let Expo do it, keeping in mind that you have to export default component always: Also you need to import View and Button from react-native: please find below the full code:

import React from 'react';
import {
  AppRegistry,
  Text,
  View,
  Button
} from 'react-native';
import { StackNavigator } from 'react-navigation';

 class HomeScreen extends React.Component {
  static navigationOptions = {
    title: 'Welcome',
  };
  render() {
    const { navigate } = this.props.navigation;
    return (
      <View>
        <Text>Hello, Chat App!</Text>
        <Button
          onPress={() => navigate('Chat', { user: 'Lucy' })}
          title="Chat with Lucy"
        />
      </View>
    );
  }
}

 class ChatScreen extends React.Component {
  // Nav options can be defined as a function of the screen's props:
  static navigationOptions = ({ navigation }) => ({
    title: `Chat with ${navigation.state.params.user}`,
  });
  render() {
    // The screen's current route is passed in to `props.navigation.state`:
    const { params } = this.props.navigation.state;
    return (
      <View>
        <Text>Chat with {params.user}</Text>
      </View>
    );
  }
}

const  SimpleAppNavigator = StackNavigator({
  Home: { screen: HomeScreen },
  Chat: { screen: ChatScreen }
});

const AppNavigation = () => (
  <SimpleAppNavigator  />
);

export default class App extends React.Component {
  render() {
    return (
        <AppNavigation/>
    );
  }
}

Solution 2

Additional Info: When you are nesting child components, you need to pass navigation as prop in parent component. //parent.js <childcomponent navigation={this.props.navigation}/>

And you can access navigation like this

//child.js

enter image description here this.props.navigation.navigate('yourcomponent');

Reference: https://reactnavigation.org/docs/en/connecting-navigation-prop.html

Solution 3

As Bobur has said in his answer, the navigation prop isn't passed to children of the routed component. To give your components access to navigation you can pass it as a prop to them, BUT there is a better way.

If you don't want to pass the navigation prop all the way down your component hierarchy, you can use useNavigation instead. (Which in my opinion is just cleaner anyways, and reduces the amount of code we have to write):

function MyBackButton() {
  const navigation = useNavigation();

  return (
    <Button
      title="Back"
      onPress={() => {
        navigation.goBack();
      }}
    />
  );
}

https://reactnavigation.org/docs/use-navigation/

This is just really nice because if you have multiple levels of components you wont have to continuously pass the navigation object as props just to use it. Passing navigation just once requires us to 1. Add a prop to the component we want to pass it to. 2. Pass the prop from the parent component. 3. Use the navigation prop to navigate. Sometimes we have to repeat steps 1 and 2 to pass the prop all the way down to the component that needs to use navigation. We can condense steps 1 and 2, no matter how many times they are repeated, into a single useNavigation call with this method.

I think it is best.

Share:
74,329

Related videos on Youtube

user3676224
Author by

user3676224

Updated on July 09, 2022

Comments

  • user3676224
    user3676224 almost 2 years

    Im following this tutorial https://reactnavigation.org/docs/intro/ and im running into a bit of issues.

    Im using the Expo Client app to render my app every time and not a simulator/emulator.

    my code is seen down below.

    I originally had the "SimpleApp" const defined above "ChatScreen" component but that gave me the following error:

    Route 'Chat' should declare a screen. For example: ...etc

    so I moved the decleration of SimpleApp to just above "AppRegistry" and that flagged a new error

    Element type is invalid: expected string.....You likely forgot to export your component..etc

    the tutorial did not add the key words "export default" to any component which I think it may have to do with the fact that im running it on the Expo app? so I added "export default" to "HomeScreen" and the error went away.

    The new error that I cant seem to get rid off(based on the code below) is the following:

    undefined is not an object (evaluating 'this.props.navigation.navigate')

    I can't get rid of it unless I remove the "{}" around "const {navigate}" but that will break the navigation when I press on the button from the home screen

    import React from 'react';
    import {AppRegistry,Text,Button} from 'react-native';
    import { StackNavigator } from 'react-navigation';
    
    export default class HomeScreen extends React.Component {
      static navigationOptions = {
        title: 'Welcome',
      };
      render() {
        const { navigate } = this.props.navigation;
        return (
          <View>
            <Text>Hello, Chat App!</Text>
            <Button
              onPress={() => navigate('Chat')}
              title="Chat with Lucy"
            />
          </View>
        );
      }
    }
    
    
    
    class ChatScreen extends React.Component {
      static navigationOptions = {
        title: 'Chat with Lucy',
      };
      render() {
        return (
          <View>
            <Text>Chat with Lucy</Text>
          </View>
        );
      }
    }
    
    const SimpleApp = StackNavigator({
      Home: { screen: HomeScreen },
      Chat: { screen: ChatScreen },
    });
    AppRegistry.registerComponent('SimpleApp', () => SimpleApp);
    
    • Milan Gulyas
      Milan Gulyas almost 7 years
      Seems like this.props.navigation is undefined when first rendered. You can try removing the line const { navigate } = this.props.navigation; and using onPress={() => this.props.navigation.navigate('Chat')} so it will access the object only later.
    • user3676224
      user3676224 almost 7 years
      I tried that, I got prompted to press on the button, but when i did i ran in to this error, "undefined is not an object (evaluating '_this2.props.navigation.navigate')" And I do have react-navigation npm module installed
    • Milan Gulyas
      Milan Gulyas almost 7 years
      For me the navigation works fine, just needed to import View from react-native, but I am not running it in Expo.
    • Andrew Koster
      Andrew Koster over 4 years
      If I was designing a navigation API to be as obtuse and fragile as possible, I could not do worse than React navigation.
  • user3676224
    user3676224 almost 7 years
    Thank you so much! it worked! Can you elaborate more on the part where i shouldn't do appregistration myself with expo ? And just to confirm, I always need to export a default component WHICH will be rendered initially ? Also, Any reason you made AppNavigation and instance of SimpleAppNavigator ? is this best practice?
  • Ahmed Khaled Mohamed
    Ahmed Khaled Mohamed almost 7 years
    so normally if you are testing without Expo you would register your app with for example: AppRegistry.registerComponent('SimpleApp', () => SimpleApp); But with Expo it will take the root Component exported as default and it will show it in the Expo app: 'export default class App extends React.Component { render() { return ( <AppNavigation/> ); } }' don't forget to mark the answer as the correct answer.
  • user3676224
    user3676224 almost 7 years
    done! could you also explain why you placed the simpleAppNavigator into AppNavigation and then rendered into a different component ? is that best practice?
  • Ahmed Khaled Mohamed
    Ahmed Khaled Mohamed almost 7 years
    Here it might look not important.. but in general you wanna have this separation.. because your navigator could be in another file only concerned with this part of the routing.. but your navigation could have extended logic like for example binding with the store with redux.. and also navigation could include a combination of a tab navigator and several stack navigators for example.
  • Ricky Dam
    Ricky Dam almost 7 years
    @AhmedKhaledA.Mohamed You are a god. The docs here reactnavigation.org/docs/intro are super outdated and the example is broken right out the box. You should be the one writing the example for them haha. Spent several hours on this error. Everyone on the internet is asking this question and are super confused and running in circles. Thanks man!! (bounty for you in 23 hours)
  • eden
    eden almost 7 years
    Consider adding explanations to your answer.
  • Ahmed Khaled Mohamed
    Ahmed Khaled Mohamed almost 7 years
    Haha thanks man I appreciate your kind words and I'm glad I could help! But believe me I'm no where close to the guys working on react-navigation, I wish I was haha! Thanks again.
  • tibi
    tibi over 6 years
    thanks it works. but one thing is that when using flow it will give an error on: const {navigate} = this.props.navigation;
  • Kanan Vora
    Kanan Vora over 5 years
    Can you please provide this working demo? I was looking for the same requirement...
  • Raja C
    Raja C almost 4 years
    Thank you. This really helped me in my initial struggle with react-native to solve the undefined error
  • kwoxer
    kwoxer almost 4 years
    Does not work anymore. Module '"./node_modules/react-navigation/typescript/react-navigatio‌​n"' has no exported member 'StackNavigator'.
  • ReZ
    ReZ over 3 years
    this.props.navigation gives me this problem: Property 'navigation' does not exist on type 'Readonly<{}>
  • BertC
    BertC over 3 years
    And take away the typo's from your code: "Componet"...
  • Amon
    Amon over 3 years
    This worked for me thank you! I assumed that because I had created a screen for my component that it would receive the props.navigation however it wasn't because that component was nested in another one, not sure why that is. So I just passed it like you said.
  • ICW
    ICW about 3 years
    Ouch, I don't like having to do this, maybe it'd be nice to have it in a context. Edit: We can call useNavigation which is nice because we don't have to pass props down the component hierarchy