Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass navigation.navigate to Child Component

Building an app using react-navigation. I have a parent component that pulls from firebase and renders data in a listview. The listview render component 'ListName' has an onRowPress function but this.props.navigation.navigate comes up undefined because navigation is not in that child component's state.

Ive tried multiple ways of passing in navigation prop to the child and also importing navigation from react-navigation within the child. Nothing works.

Thanks!

Here is my rootStackNavigator:

const RootStackNavigator = StackNavigator(
  {
    Login: { screen: LoginScreen },
    Main: { screen: MainTabNavigator },
    Feedback: { screen: ProvideInstanceScreen }
  },
  {
    navigationOptions: () => ({
      //headerTitleStyle: {
        //fontWeight: 'normal',
        tabBarVisible: false,
        header: null
      //},
    }),
  }
);

Here is my Parent Component (which has navigation.navigate in its state)

import React from 'react';
import { ListView, StyleSheet, Text, Image } from 'react-native';
import { connect } from 'react-redux';
import _ from 'lodash';
import { MainButton, GenSection } from '../components/common';
import { namesFetch } from '../actions';
import ListName from '../components/ListName.js';

class ProvideScreen extends React.Component {

  static navigationOptions = {
    header: null,
  };


  componentWillMount() {
  //console.log('HOME HOME HOME  PRINT', this.props)
    this.props.namesFetch();

    this.createDataSource(this.props);
  }

  componentDidMount() {
    console.log('PROVIDE PROPS   PRINT', this.props)
    this.createDataSource(this.props);
  }

  componentWillReceiveProps(nextProps) {
    //nextProps are next set of props component is rendered with and this.props is still old props
    console.log('NEXT PROPS', nextProps)
    this.createDataSource(nextProps);
  }


  createDataSource({ names }) {
    var namesArray = names.map(function(a) {return [a.name, a.uid];});
    //console.log('NAMES ARRAY PRINT', namesArray)
    const ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1 !== r2
    });
    this.dataSource = ds.cloneWithRows(namesArray);
  }

  renderRow(user) {
    return <ListName name={user[0]} />;
  }


  render() {
    return (
      <Image
        source={require('../components/images/mainBG.png')}
        style={styles.containerStyle}>
        <Text style={styles.textStyle}>
          Provide Feedback
        </Text>
        <GenSection style={{paddingTop: 8}} />
        <ListView
          enableEmptySections
          dataSource={this.dataSource}
          renderRow={this.renderRow}
          removeClippedSubviews={false}
        />

    </Image>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 15,
    backgroundColor: '#fff',
  },
  containerStyle: {
    flex: 1,
    width: undefined,
    height: undefined,
    backgroundColor:'transparent'
  },
  textStyle:
  {
    paddingTop: 20,
    paddingLeft: 12,
    fontSize: 32,
    fontWeight: '200',
    color: '#597abc'
  }
});



const mapStateToProps = state => {
  //console.log('STATE PRINT', state.feedbackInput)
  const names = _.map(state.feedbackInput, (val) => {
    return { ...val};
  });
  //console.log('NAMES PRINT', names)
  return { names };
};  //this is lodash   .map iterates over key value pairs and run function which assigns data to groups array



export default connect(mapStateToProps, { namesFetch })(ProvideScreen);

Here is my child component (which does not have navigation.navigate in state):

import React, { Component } from 'react';
import { Text, TouchableWithoutFeedback, View } from 'react-native';
import { connect } from 'react-redux';
import { ListButton } from './common';

class ListName extends Component {
  onRowPress() {
    console.log('ON ROW PRESS  PRINT', this.props)
    this.props.navigation.navigate('Feedback', this.props);
  }

  componentDidMount() {
    //console.log('LIST NAME LIST NAME  PRINT', this.props)
  }

  render() {
    const name = this.props.name;
    //console.log('LISTNAME PRINT', name)

    return (
      <TouchableWithoutFeedback onPress={this.onRowPress.bind(this)}>
        <View>
          <ListButton>
            <Text style={styles.titleStyle}>
              {name}
            </Text>
          </ListButton>
        </View>
      </TouchableWithoutFeedback>
    );
  }
}

const styles = {
  titleStyle: {
    alignSelf: 'center',
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
  }
};


const mapStateToProps = state => {
  //console.log('NAMES PRINT', names)
  return state
};  //this is lodash   .map iterates over key value pairs and run function which assigns data to groups array


export default connect(mapStateToProps)(ListName);
like image 907
C T Avatar asked Jul 20 '17 18:07

C T


2 Answers

Base on React Navigation: https://reactnavigation.org/docs/en/connecting-navigation-prop.html

You just need to import withNavigation into child component only.

import { withNavigation } from 'react-navigation';

then export:

export default withNavigation(<YourChildComponent>);
like image 82
Nguyen Huynh Avatar answered Sep 18 '22 21:09

Nguyen Huynh


One way is to have a onPress handler in your ProvideScreen component that is passed down to your list item component and thus in ProvideScreen's onRowPress function, you will have access to this.props.navigation.

In ProvideScreen:

class ProvideScreen extends Component {
  ...
  onRowPress(someRowData) {
    this.props.navigation.navigate('Feedback', { someRowData });
  }
  ...

  renderRow(user) {
    return <ListName name={user[0]} onRowPress={this.onRowPress} />;
  }
}

In ListName:

class ListName extends Component {
  ...
  onRowPress() {
    this.props.onRowPress(someData);
  }
  ...
}

Of course, don't forget about binding the functions to this scope when you are using event handlers. e.g. in constructor:

this.onRowPress = this.onRowPress.bind(this);

An alternative define onRowPress with an arrow functions:

onRowPress = () => {
 this.props.navigation.navigate...
}
like image 29
hyb175 Avatar answered Sep 17 '22 21:09

hyb175