2

I'm having trouble calling react navigation methods from custom components outside of my original screens, specifically the one I'm working on right now is trying to call goBack() in a back arrow of a custom header component I made (code below). The error message I'm getting when I click the back arrow is:

undefined is not an object (evaluating '_this2.props.navigation.goBack')

Here is the code:

// HeaderText.js
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Platform } from 'react-native';
import { Icon } from 'expo';

export class HeaderText extends React.Component {
  render() {
    const needsBackButton = this.props.backIcon;
    if (needsBackButton) {
        return(
            <View style={[styles.headerStyle,styles.buttonHeaderStyle]}>
                <TouchableOpacity onPress={() => this.props.navigation.goBack()} style={styles.backButtonStyles}><Icon.Ionicons size={25} style={{ color: '#fff', fontWeight: 'bold' }} name={Platform.OS === 'ios' ? `ios-arrow-back` : 'md-arrow-back'} /></TouchableOpacity>
                <Text style={styles.textStyle}>{this.props.headerText}</Text>
                <View style={styles.emptyViewStyles} />
            </View>
            );
    } else {
        return(
            <View style={styles.headerStyle}>
                <Text style={styles.textStyle}>{this.props.headerText}</Text>
            </View>
            );
    }
  }
}

Here is the screen I'm putting that HeaderText component in:

// SubmitReferralScreen.js
import React from 'react';
import {
  Image,
  Platform,
  ScrollView,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
  ImageBackground
} from 'react-native';

import { MonoText } from '../../components/general/StyledText';
import { HeaderText } from '../../components/general/HeaderText';
import { HomeScreenContainer } from '../../components/homeScreen/HomeScreenContainer';
import { IconButton } from '../../components/general/IconButton';
import { StatusInfo } from '../../constants/StatusInfo';
import SvgUri from 'react-native-svg-uri';

export default class SubmitReferralScreen extends React.Component {

  static navigationOptions = {
    header: null,
  };

  render() {
    return (
        <View style={{flex: 1, width: '100%',justifyContent: 'center', alignItems: 'center'}}>
          <ImageBackground source={require('../../assets/images/background.png')} style={{width: '100%', height: '100%', flex: 1, justifyContent: 'flex-start', alignItems: 'center', backgroundColor: 'background-color: rgba(0, 0, 0, 0.5)',}}>
            <HeaderText backIcon='true' headerText='New Referral' />
              <Text>Submit referral here!</Text>
          </ImageBackground>
        </View>
    );
  }

}

And here is my Stack Navigator for the referral Screens:

// MainTabNavigator.js
const ReferralStack = createStackNavigator({
  Referrals: ReferralScreen,
  MakeReferral: SubmitReferralScreen,
});

I've looked at this StackOverflow answer: Getting undefined is not an object evaluating _this.props.navigation And the answer there was to put only navigation.navigate(YourScreen). I tried that, and the error I got said "cannot find variable navigation".

How can I call navigation props from custom react native components?

Adam McGurk
  • 186
  • 1
  • 19
  • 54

2 Answers2

3

By default only screen components are provided with the navigation prop. You can either use library provided ways of hooking up arbitrary components to the navigation state, or you can pass navigation as a prop manually.

Option #1. Using withNavigation: React navigation exports a higher-order component through which you can inject the navigation props into any component you want. To do this, you can do something like:

  1. Don't immediately export the HeaderText component class (remove export from that line)

  2. At the bottom of that file add export default withNavigation( HeaderText );

or if you don't want to use a default export and keep it as a named export, instead do:

const NavigationConnected = withNavigation( HeaderText );
export { NavigationConnected as HeaderText };

Option #2. Passing navigation as prop: In your SubmitReferralScreen component you can simply pass this.props.navigation as a prop to the HeaderText component like: <HeaderText navigation={ this.props.navigation } />

casieber
  • 7,264
  • 2
  • 20
  • 34
  • 1
    Awesome, I used option 1!!! The problem was, I was doing it like this: `export withNavigation( HeaderText );` and not the way you did it, that works!!!! – Adam McGurk Nov 08 '18 at 01:52
  • Great solutions! I used Option #1 because I have lot of child components and did not want to set navigation props 2-3 times after each other. – Steffo Dimfelt Jun 18 '20 at 11:52
0

It's because your navigation prop didn't found where is the navigation's value prop from the parent. Better you make HeaderText component using regular arrow function, like this;

const HeaderText = ({ needsBackButton }) => {
  if(needsBackButton) {
    return (
       <View style={[styles.headerStyle,styles.buttonHeaderStyle]}>
            <TouchableOpacity onPress={() => this.props.navigation.goBack()} style={styles.backButtonStyles}><Icon.Ionicons size={25} style={{ color: '#fff', fontWeight: 'bold' }} name={Platform.OS === 'ios' ? `ios-arrow-back` : 'md-arrow-back'} /></TouchableOpacity>
            <Text style={styles.textStyle}>{this.props.headerText}</Text>
            <View style={styles.emptyViewStyles} />
        </View>
    )
  }
  return (
    // another component
  )
}

And then, You can simply use useNavigation() to access navigation prop from any screen/component.

First, import useNavigation on component that handled function of the moving screen.

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

Create some constant to reference this module:

const navigation = useNavigation()

And then, simply use this on your TouchableOpacity's onPress prop like this;

<TouchableOpacity
  onPress={() => navigation.goBack()}
  style={styles.backButtonStyles}
>
  //...
</ TouchableOpacity>

Get the complete documentation on this: https://reactnavigation.org/docs/connecting-navigation-prop/