0

I am getting undefined is not an object evaluating _this.props.navigation. Here is my code.

I want to use the in multiple screens so I have to extract it out and call it in any I need it in.

I have tried https://github.com/react-navigation/react-navigation/issues/2198#issuecomment-316883535 to no luck.

Category.js

import React, {Component} from 'react';
import {View, FlatList} from 'react-native';
import {ListItem} from 'react-native-elements'

import {AppRegistry, TouchableOpacity, ActivityIndicator} from 'react-native';
import {SearchHeader} from '../SearchHeader';

export default class Category extends Component {
  constructor() {
    super();
    this.state = {
      list: [],
    };
    this.onPress = this.onPress.bind(this);
  }

  static navigationOptions = {
    title: 'Categories',
    headerStyle: {backgroundColor: '#ffb30c'},
  };

  renderSeparator = () => {
    return (
      <View
        style={{
          height: 1,
          width: "98%",
          backgroundColor: "#CED0CE",
          marginLeft: "1%",
          marginRight: "1%"
        }}
      />
    );
  };

  _keyExtractor = (item, index) => item.name;

  renderHeader = () => {
    return (<SearchHeader />);
  };

  renderFooter = () => {
    if (!this.state.loading) return null;

    return (
      <View
        style={{
          paddingVertical: 20,
          borderTopWidth: 1,
          borderColor: "#CED0CE"
        }}
      >
        <ActivityIndicator animating size="large"/>
      </View>
    );
  };

  onPress = (item) => {
    this.props.navigation.navigate('SpecTypeScreen',{cat:item});
  };

  search = () => {
  };

  render() {
    return (
      <FlatList
        data={this.state.list}
        renderItem={({item}) => (
          <TouchableOpacity onPress={() => this.onPress(item)}>
            <ListItem
              title={`${item.name}`}
              containerStyle={{borderBottomWidth: 0}}

            />
          </TouchableOpacity>
        )}
        keyExtractor={this._keyExtractor}
        ItemSeparatorComponent={this.renderSeparator}
        ListHeaderComponent={this.renderHeader}
        ListFooterComponent={this.renderFooter}
      />
    );
  }
}

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

SearchHeader.js

import React, {Component} from 'react';
import Autocomplete from 'react-native-autocomplete-input';
import {
  AppRegistry,
  View,
  StyleSheet,
  Platform,
  Text,
  TouchableOpacity,
} from 'react-native';
import {withNavigation} from 'react-navigation';
import colors from './config/colors';
import normalize from './config/normalizeText';

export class SearchHeader extends Component {
  constructor() {
    super();
    this.state = {
      list: [],
    };
  }

  search = (term) => {
    if (term.length > 2) {
      fetch("https://myUrl?term=" + encodeURI(term))
        .then((response) => response.json())
        .then((responseJson) => {
          this.setState({list: responseJson});
          console.log(responseJson);
        })
        .catch((error) => {
          console.error(error)
        });
    }
    else{
      this.setState({list: []});
    }
  };
  onPress = (item) => {
    this.props.navigation.navigate('ProductScreen',{spec:item});
  };
  render() {
    return (
      <View style={[
        styles.container, styles.containerLight
      ]}>
        <Autocomplete placeholder="Search Specs & Approvals..."
                      autoCorrect={false}
                      onChangeText={this.search}
                      data={this.state.list}
                      containerStyle={{backgroundColor: "#d71201"}}
                      inputStyle={{backgroundColor: "#fff"}}
                      renderItem={({ id, specification }) => (
                        <TouchableOpacity style={styles.autocompleteContainer} onPress={this.onPress.bind(this, specification)}>
                          <Text style={styles.itemText}>
                            {specification}
                          </Text>
                          <View
                            style={{
                              height: 1,
                              width: "98%",
                              backgroundColor: "#CED0CE",
                              marginLeft: "1%",
                              marginRight: "1%"
                            }}
                          />
                        </TouchableOpacity>
                      )}
                      style={[
                        styles.input,
                        styles.inputLight,
                        {borderRadius: Platform.OS === 'ios' ? 15 : 20},
                        {paddingRight: 50}
                      ]}/>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    borderTopWidth: 1,
    borderBottomWidth: 1,
    borderBottomColor: '#000',
    borderTopColor: '#000',
    backgroundColor: "#d71201",
    maxHeight:70
  },
  containerLight: {
    borderTopColor: '#e1e1e1',
    borderBottomColor: '#e1e1e1',
  },
  input: {
    paddingLeft: 26,
    paddingRight: 19,
    margin: 8,
    borderRadius: 3,
    overflow: 'hidden',
    backgroundColor: colors.grey5,
    fontSize: normalize(14),
    color: colors.grey3,
    height: 40,
    ...Platform.select({
      ios: {
        height: 30,
      },
      android: {
        borderWidth: 0,
      },
    }),
  },
  inputLight: {
    backgroundColor: "#fff"
  },
  autocompleteContainer: {
    backgroundColor:"#fff",
    marginLeft: 10,
    marginRight: 10
  },
  itemText: {
    fontSize: 15,
    margin: 5,
    marginLeft: 20,
    paddingTop:5,
    paddingBottom:5
  },
  descriptionContainer: {
    backgroundColor: '#F5FCFF',
    marginTop: 8
  },
  infoText: {
    textAlign: 'center'
  },
  titleText: {
    fontSize: 18,
    fontWeight: '500',
    marginBottom: 10,
    marginTop: 10,
    textAlign: 'center'
  },
  directorText: {
    color: 'grey',
    fontSize: 12,
    marginBottom: 10,
    textAlign: 'center'
  },
  openingText: {
    textAlign: 'center'
  }
});

AppRegistry.registerComponent('SearchHeader', () => SearchHeader);
0

2 Answers 2

1

You need to pass the navigation prop down. Try this:

renderHeader = () => {
   return (<SearchHeader navigation={this.props.navigation} />);
};
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for that @Loïc Bellemare-Alford
0

You need to wrap your component with withNavigation(Component)

Example: AppRegistry.registerComponent('SearchHeader', () => withNavigation(SearchHeader));

The point of withNavigation was so that you wouldn't need to pass navigation as a prop. Especially useful when you're passing through multiple children.

1 Comment

I didn't suggest it because it doesn't seem to be the "recommended" way. If you check the documentation they say "It's useful when you cannot pass the navigation prop into the component directly, or don't want to pass it in case of a deeply nested child." reactnavigation.org/docs/with-navigation.html But I agree with you that it's a "cleaner way of doing it".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.