20

I'm just starting to wrap my head around React Native and am using Redux for management of state, the NativeBase library for my UI components and react-native-router-flux is handling navigation between views.

Currently I'm building a basic list that is created from an array of guest objects. The list is stored in the Redux store and I'm able to access it and display accordingly. Each item in the list is associated with a guest within a guests array. I'd like to make each item in the list touchable, and then pass the relevant guest object as a property to the next view to display details.

To do so I'm using the onPress function which is a standard function associated with the ListItem component (see NativeBase docs here). I've also followed the documentation for react-native-router-flux and defined the navigation action outside of the component itself so that the ListItem calls it when pressed and not each time it renders.

My problem is that I am finding that the onPress={goToView2(guest)} function is being called each time the ListItem is rendered rather than specifically when the ListItem is pressed.

I am sure it must be something simple that I have omitted. Any suggestions?

View1.js - view that displays initial list of guests:

import React, { Component } from 'react';
import { Container, Header, Title, Content, Footer, FooterTab, Button, Icon,
  Text, List, ListItem } from 'native-base';
import { connect } from 'react-redux';
import { Actions as NavigationActions } from 'react-native-router-flux';

class View1 extends Component {
  render() {

    // This is the function that runs every time a ListItem component is rendered. 
    // Why is this not only running on onPress?

    const goToView2 = (guest) => {
      NavigationActions.view2(guest);
      console.log('Navigation router run...');
    };

    return (
      <Container>
        <Header>
          <Title>Header</Title>
        </Header>


        <Content>
          <List
            dataArray={this.props.guests}
            renderRow={(guest) =>
              <ListItem button onPress={goToView2(guest)}>
                <Text>{guest.name}</Text>
                <Text note>{guest.email}</Text>
              </ListItem>
            }
          >
          </List>
        </Content>

        <Footer>
          <FooterTab>
            <Button transparent>
              <Icon name='ios-call' />
            </Button>
          </FooterTab>
        </Footer>
      </Container>
    );
  }
}

const mapStateToProps = state => {
  console.log('mapStateToProps state', state);
  return { guests: state.guests };
};

export default connect(mapStateToProps)(View1);

View2.js - view that displays details of the selected guest from View1.js:

import React, { Component } from 'react';
import { Container, Header, Title, Content, Footer, FooterTab, Button, Icon,
  Text, List, ListItem } from 'native-base';

class View2 extends Component {
    render() {
        console.log('View2 props: ', this.props);

        return (
            <Container>
                <Header>
                    <Title>Header</Title>
                </Header>

                <Content>
                <Content>
                <List>
                    <ListItem>
                        <Text>{this.props.name}</Text>
                    </ListItem>
                </List>
            </Content>
                </Content>

                <Footer>
                    <FooterTab>
                        <Button transparent>
                            <Icon name='ios-call' />
                        </Button>
                    </FooterTab>
                </Footer>
            </Container>
        );
    }
}

export default View2;
oldo.nicho
  • 1,582
  • 1
  • 18
  • 29

2 Answers2

48

Try to do <ListItem button onPress={() => {goToView2(guest)}}

philippsh
  • 758
  • 9
  • 16
  • 2
    Legend! I've been racking my brain for a ages... Why did the way that I was typing it not work? – oldo.nicho Oct 27 '16 at 02:44
  • 5
    @oldo.nicho we are passing a callback there. If you would do it like onPress={goToView} without executing the function, it would work. But when you need to pass the parameter you should execute a function that will execute a function with the needed param. I'm sorry if explaination is bad, it's late night here)) – philippsh Oct 27 '16 at 02:51
  • 1
    Thank you @philippsh I've got a lot to learn and am blown away by the willingness of the stackoverflow community to help out. What you write makes sense and I'll look into it more. – oldo.nicho Oct 27 '16 at 02:56
  • 2
    Just to add some clarity, the way I'd explain it is that you were saying when the ListItem is being rendered, call the function goToView2 and pass the return value to back ListItem to call when it's pressed. So that's why it keeps being called by itself, even though it wasn't being pressed. – Pedram Nov 01 '16 at 23:10
2
const goToView2 = (guest) => {
      NavigationActions.view2(guest);
      console.log('Navigation router run...');
    };

<ListItem button onPress={this.goToView2(guest)}>

if you're using arrow function in the function then its just this.goToView2(guest) ...writing arrow function inside a render method causes performance issues...even though its negligible, its better to avoid it

rajeshzmoke
  • 120
  • 1
  • 6
  • If it's negligible, why avoid it? – Rambatino Aug 30 '18 at 06:25
  • Can you link to the evidence for that? – Rambatino Oct 05 '18 at 09:03
  • because when the number of such functions increases inside the render function it can add up and slow down the application, and also i've faced issues where using the arrow function inside the render method caused infinite function call invocations – rajeshzmoke Oct 06 '18 at 10:12
  • I just don't think that's correct. Fine if you're calling the function over and over again and it's trying to re-render that's a problem. But you've not explained your point regarding _why the arrow syntax is problematic_ – Rambatino Oct 07 '18 at 07:31