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

6.7k views Asked by At

I'm trying to learn react native for the first time. I tried to introduce a stacknavigator but the line const {navigate} = this.props.navigation; is causing the error:

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

Here is my code:

import React, { Component } from "react";
import { StackNavigator } from "react-navigation";
import { AppRegistry, Text, View } from "react-native";

export default class App extends Component {
  static navigationOptions = {
    title: "Login",
    headerStyle: {
      backgroundColor: "#000000"
    },
    headerTitleStyle: {
      color: "#fff"
    }
  };

  constructor(props) {
    super(props);
  }
  render() {
    console.log(this.props);

    const { navigate } = this.props.navigation;
    return (
      <View>
        <Text>Hello</Text>
      </View>
    );
  }
}

const myscreens = StackNavigator({
  Home: { screen: App }
});
AppRegistry.registerComponent("app", () => myscreens);

What am I doing wrong and how do I fix this?

I should also mention that props is empty in the render function and in the constructor.

here's my package.json incase it matters

{
  "name": "myapp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "jest"
  },
  "dependencies": {
    "react": "16.0.0-alpha.12",
    "react-native": "0.48.3",
    "react-navigation": "git+https://github.com/react-community/react-navigation.git"
  },
  "devDependencies": {
    "babel-jest": "21.0.2",
    "babel-preset-react-native": "4.0.0",
    "jest": "21.1.0",
    "react-test-renderer": "16.0.0-alpha.12"
  },
  "jest": {
    "preset": "react-native"
  }
}

And here's my index.android.js

import React, { Component } from 'react';
import App from './components/app';
import {
  AppRegistry,
  View
} from 'react-native';

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


AppRegistry.registerComponent('myapp', () => myapp);
1

There are 1 answers

0
Michael Cheng On BEST ANSWER

Two errors:

  1. You shouldn't be calling AppRegistry twice like that. You can remove it from your app.js file.

  2. You are misunderstanding how react-navigation's routers work. StackNavigator (and Tab and Drawer) are components that need to be rendered either directly (e.g., what you pass to AppRegistry [A]) or at some point in your application [B].

So to fix this, you will want to export myscreens instead of App. To illustrate both ways to do this:

A. You can see an example of this in the docs, but since you break up your code into two files, this is what it would look like:

./components/app.js

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

class App extends Component {
  static navigationOptions = {
    title: 'Login',
    headerStyle: {
      backgroundColor: '#000000',
    },
    headerTitleStyle: {
      color: '#fff',
    },
  };

  constructor(props) {
    super(props);
  }
  render() {
    console.log(this.props);

    const { navigate } = this.props.navigation;
    return (
      <View>
        <Text>Hello</Text>
      </View>
    );
  }
}

const myscreens = StackNavigator({
  Home: { screen: App },
});

export default myscreens;

index.android.js

import { AppRegistry } from 'react-native';
import myscreens from './components/app';

AppRegistry.registerComponent('myapp', () => myscreens);

B. You will render the StackNavigator in another class and then export the class that renders it. This fits more in line with what you are already doing and is more flexible in the long run (ex: you will need to do this if you use redux at some point), so you should probably do it this way:

./components/app.js - Note the casing change for myscreens to MyScreens. This is needed as React Native will complain about this as lowercase JSX tags are considered to be HTML. Using AppRegistry directly didn't trigger this error as you aren't using myscreens in JSX.

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

class App extends Component {
  static navigationOptions = {
    title: 'Login',
    headerStyle: {
      backgroundColor: '#000000',
    },
    headerTitleStyle: {
      color: '#fff',
    },
  };

  constructor(props) {
    super(props);
  }
  render() {
    console.log(this.props);

    const { navigate } = this.props.navigation;
    return (
      <View>
        <Text>Hello</Text>
      </View>
    );
  }
}

const MyScreens = StackNavigator({
  Home: { screen: App },
});

export default MyScreens;

index.android.js

import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import MyScreens from './components/app';

export default class myapp extends Component {
  render() {
    return <MyScreens />;
  }
}

AppRegistry.registerComponent('myapp', () => myapp);