title: FlatList renderItem is called multiple times
body: <p>I'm using FlatList to display data from an API call:</p>
  
  <pre><code>render() {
    const { navigation } = this.props;
    const animating = this.state.animating;
  
    return (
      &lt;View style={styles.container}&gt;
        &lt;ActivityIndicator
          animating = {animating}
          color = '#E3A141'
          size = {120}
          style = {styles.activityIndicator}
        /&gt; 
        &lt;FlatList                    
          ref='listRef'
          data={this.props.data}
          renderItem={this.renderItem}
          keyExtractor={(item, index) =&gt; index.toString()}
        /&gt;   
        &lt;SocialFooter navigation={navigation}/&gt;
      &lt;/View&gt;
    )
  }
  
  renderItem({item, index}) {
    console.log("renderItem(item): ", item, "index: ", index)
  }
  </code></pre>
  
  <p>The returned data is an array with 3 objects and an array, as you can see in the output renderItem() is called once per object in the array:</p>
  
  <pre><code>renderItem(item):  Object {
  12:47:38:   "antiparasitario": "SI",
  12:47:38:   "color": "BLANCO",
  12:47:38:   "contrato": "00345",
  12:47:38:   "datoCobol": 1,
  12:47:38:   "dtomedicamentos": "SI",
  12:47:38:   "dtovacunas": "SI",
  12:47:38:   "especie": "01",
  12:47:38:   "extraccsangre": "NO",
  12:47:38:   "fecnac": "2013-05-01",
  12:47:38:   "hayPendientes": 0,
  12:47:38:   "nombre": "ASTOR",
  12:47:38:   "orden": "01",
  12:47:38:   "ordenLocal": "01",
  12:47:38:   "peso": "030.000",
  12:47:38:   "raza": 107,
  12:47:38:   "rutafoto": "",
  12:47:38:   "sexo": "M",
  12:47:38:   "sociode": "MASCOTA24",
  12:47:38:   "traslado": "SI",
  12:47:38: } index:  0
  12:47:39: renderItem(item):  Object {
  12:47:39:   "antiparasitario": "SI",
  12:47:39:   "color": "BALNCO",
  12:47:39:   "contrato": "00345",
  12:47:39:   "datoCobol": 1,
  12:47:39:   "dtomedicamentos": "SI",
  12:47:39:   "dtovacunas": "SI",
  12:47:39:   "especie": "01",
  12:47:39:   "extraccsangre": "NO",
  12:47:39:   "fecnac": "2017-05-01",
  12:47:39:   "hayPendientes": 0,
  12:47:39:   "nombre": "APACHE",
  12:47:39:   "orden": "02",
  12:47:39:   "ordenLocal": "02",
  12:47:39:   "peso": "025.000",
  12:47:39:   "raza": 107,
  12:47:39:   "rutafoto": "",
  12:47:39:   "sexo": "M",
  12:47:39:   "sociode": "MASCOTA24",
  12:47:39:   "traslado": "SI",
  12:47:39: } index:  1
  12:47:39: renderItem(item):  Object {
  12:47:39:   "antiparasitario": "SI",
  12:47:39:   "color": "MARRON",
  12:47:39:   "contrato": "00345",
  12:47:39:   "datoCobol": 1,
  12:47:39:   "dtomedicamentos": "SI",
  12:47:39:   "dtovacunas": "SI",
  12:47:39:   "especie": "01",
  12:47:39:   "extraccsangre": "NO",
  12:47:39:   "fecnac": "2015-05-01",
  12:47:39:   "hayPendientes": 0,
  12:47:39:   "nombre": "CORA",
  12:47:39:   "orden": "03",
  12:47:39:   "ordenLocal": "03",
  12:47:39:   "peso": "005.000",
  12:47:39:   "raza": 43,
  12:47:39:   "rutafoto": "",
  12:47:39:   "sexo": "H",
  12:47:39:   "sociode": "MASCOTA24",
  12:47:39:   "traslado": "SI",
  12:47:39: } index:  2
  12:47:39: renderItem(item):  Array [
  12:47:39:   Object {
  12:47:39:     "dni": "0303456",
  12:47:39:     "socioID": 2020,
  12:47:39:     "titular": "Jonny Melaslavo",
  12:47:39:   },
  12:47:39: ] index:  3
  12:47:39: renderItem(item):  Object {
  12:47:39:   "antiparasitario": "SI",
  12:47:39:   "color": "BLANCO",
  12:47:39:   "contrato": "00345",
  12:47:39:   "datoCobol": 1,
  12:47:39:   "dtomedicamentos": "SI",
  12:47:39:   "dtovacunas": "SI",
  12:47:39:   "especie": "01",
  12:47:39:   "extraccsangre": "NO",
  12:47:39:   "fecnac": "2013-05-01",
  12:47:39:   "hayPendientes": 0,
  12:47:39:   "nombre": "ASTOR",
  12:47:39:   "orden": "01",
  12:47:39:   "ordenLocal": "01",
  12:47:39:   "peso": "030.000",
  12:47:39:   "raza": 107,
  12:47:39:   "ruta_img": 3,
  12:47:39:   "rutafoto": "",
  12:47:39:   "sexo": "M",
  12:47:39:   "sociode": "MASCOTA24",
  12:47:39:   "traslado": "SI",
  12:47:39: } index:  0
  12:47:39: renderItem(item):  Object {
  12:47:39:   "antiparasitario": "SI",
  12:47:39:   "color": "BALNCO",
  12:47:39:   "contrato": "00345",
  12:47:39:   "datoCobol": 1,
  12:47:39:   "dtomedicamentos": "SI",
  12:47:39:   "dtovacunas": "SI",
  12:47:39:   "especie": "01",
  12:47:39:   "extraccsangre": "NO",
  12:47:39:   "fecnac": "2017-05-01",
  12:47:39:   "hayPendientes": 0,
  12:47:39:   "nombre": "APACHE",
  12:47:39:   "orden": "02",
  12:47:39:   "ordenLocal": "02",
  12:47:39:   "peso": "025.000",
  12:47:39:   "raza": 107,
  12:47:39:   "ruta_img": 3,
  12:47:39:   "rutafoto": "",
  12:47:39:   "sexo": "M",
  12:47:39:   "sociode": "MASCOTA24",
  12:47:39:   "traslado": "SI",
  12:47:39: } index:  1
  12:47:39: renderItem(item):  Object {
  12:47:39:   "antiparasitario": "SI",
  12:47:39:   "color": "MARRON",
  12:47:39:   "contrato": "00345",
  12:47:39:   "datoCobol": 1,
  12:47:39:   "dtomedicamentos": "SI",
  12:47:39:   "dtovacunas": "SI",
  12:47:39:   "especie": "01",
  12:47:39:   "extraccsangre": "NO",
  12:47:39:   "fecnac": "2015-05-01",
  12:47:39:   "hayPendientes": 0,
  12:47:39:   "nombre": "CORA",
  12:47:39:   "orden": "03",
  12:47:39:   "ordenLocal": "03",
  12:47:39:   "peso": "005.000",
  12:47:39:   "raza": 43,
  12:47:39:   "ruta_img": 3,
  12:47:39:   "rutafoto": "",
  12:47:39:   "sexo": "H",
  12:47:39:   "sociode": "MASCOTA24",
  12:47:39:   "traslado": "SI",
  12:47:39: } index:  2
  12:47:39: renderItem(item):  Array [
  12:47:39:   Object {
  12:47:39:     "dni": "0303456",
  12:47:39:     "socioID": 2020,
  12:47:39:     "titular": "Jonny Melaslavo",
  12:47:39:   },
  12:47:39: ] index:  3
  </code></pre>
  
  <p>This is the fetch call:</p>
  
  <pre><code>function makeDataRequest(token, nro_socio) {
    let datos_socio = [];
    fetch('http://www.api/' + nro_socio, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
          'token': token
        },
      }).then((response) =&gt; response.json())
      .then((responseJson) =&gt; {
        if (responseJson.errores) {
          dispatch({
            type: DATA_AVAILABLE,
            data: ['sin_serv_vet']
          });
        } else {
          let responseObj = responseJson.mascotas;
          if (responseObj == '') {
            dispatch({
              type: DATA_AVAILABLE,
              data: ['sin_mascotas']
            });
          }
          datos_socio.push({
            titular: responseJson.titular,
            dni: responseJson.doc,
            socioID: nro_socio
          });
          responseObj.push(datos_socio);
          dispatch({
            type: DATA_AVAILABLE,
            data: responseObj
          });
        }
      })
      .catch((error) =&gt; {
        console.error(error);
      });
  }
  </code></pre>
  
  <p>I've found lots of similar posts and they say is a react native bug, what can i do?. Thanks</p>
  
  <p><strong>Edit:</strong></p>
  
  <pre><code>class UserPage extends Component {
  
      static navigationOptions = { header: null }
  
      constructor(props) {
          super(props);
          this.state = {
              animating: true,
              isModalVisible: false
          };
          dni = props.match.params.username;           
          this.props.getData(dni);
          this.renderItem = this.renderItem.bind(this);
      }
  
      componentWillReceiveProps(nextProps) {             
          this.closeActivityIndicator();
          if (nextProps.data == "dni_incorrecto") {
              this.props.history.push('/'+"dni_incorrecto");
          } else if (nextProps.data == "sin_serv_vet") {
              this.props.history.push('/'+"sin_serv_vet");
          } else if (nextProps.data == "sin_mascotas") {
              this.props.history.push('/'+"sin_mascotas");
          }
      }
  
      closeActivityIndicator() {
          this.setState({ 
              animating: false 
          })
      }
  
      render() {
          return null;
          console.log("data length: ", this.props.data.length);
          if (this.props.data.length) { 
              const datosSocio = this.props.data[0].datos_socio;
  
              return ( 
                  &lt;View&gt;
                      &lt;View style={styles.header_container}&gt;
                          &lt;Image source={require('./img/logo-mini.png')} style={styles.logo_img} /&gt;
                          &lt;Link to="/" style={styles.back_link} underlayColor="#f0f4f7"&gt;
                              &lt;Image  
                                  source={require("./img/back.png")}
                                  style={styles.back_img}
                              /&gt;
                          &lt;/Link&gt;
                      &lt;/View&gt;
                      &lt;View style={styles.container_credential}&gt;
                          &lt;Image source={require('./img/base-face-image.png')} style={styles.customer_img} /&gt;
                          &lt;View style={styles.credential_details}&gt;
                              &lt;Text style={styles.customer_fullName}&gt;
                                  {datosSocio.titular} 
                              &lt;/Text&gt;
                              &lt;Text style={styles.customer_member_id}&gt;
                                  Socio ID: {datosSocio.socioID}                         
                              &lt;/Text&gt;
                              &lt;Text style={styles.customer_dni}&gt;
                                  DNI: {datosSocio.dni}                
                              &lt;/Text&gt;
                              &lt;Text style={styles.credential_notice_title}&gt;
                                  ¡IMPORTANTE! 
                              &lt;/Text&gt;
                              &lt;Text style={styles.credential_notice_content}&gt;
                                  El uso de esta credencial debe ser acompañado por el DNI del titular.
                              &lt;/Text&gt;
                          &lt;/View&gt;
                      &lt;/View&gt;
                      &lt;View style={styles.container_mascotas_list_title}&gt; 
                          &lt;Text style={styles.mascotas_list_title_text_first}&gt;Mis&lt;/Text&gt;&lt;Text style={styles.mascotas_list_title_text_last}&gt; mascotas:&lt;/Text&gt;                    
                      &lt;/View&gt;
                      &lt;View style={styles.mascotas_list_title_underline}&gt;&lt;/View&gt;
                      &lt;ScrollView&gt;          
                          {this.props.data.map(mascota =&gt; {
                              return ( 
                              &lt;View key={mascota.nombre}&gt;
  
                                      &lt;Text style={styles.mascotas_list_item_details_name}&gt;Nombre: {mascota.nombre}&lt;/Text&gt;                                    
                                      &lt;Text style={styles.mascotas_list_item_details_name}&gt;Raza: {getRaza(mascota.raza)}&lt;/Text&gt;
                                      &lt;Text style={styles.mascotas_list_item_details_name}&gt;Especie: {getEspecie(mascota.raza)}&lt;/Text&gt;
                                      &lt;Text style={styles.mascotas_list_item_details_sex_hair}&gt;Sexo: {mascota.sexo}&lt;/Text&gt;
                                      &lt;Text style={styles.mascotas_list_item_details_sex_hair}&gt;Color pelo: {mascota.color}&lt;/Text&gt;
  
                              &lt;/View&gt;
                              );
                          })}
                      &lt;/ScrollView&gt;
                  &lt;/View&gt;
            );
          } else {
            return null;
          }
        }
  };
  
  function getRaza(id_raza) {
      for (let i = 0; i &lt; razas.length; i++) {
          if (razas[i][0] == id_raza) {
              return razas[i][1];
          }
      }
  }
  
  function getEspecie(id_raza) {
      for (let i = 0; i &lt; razas.length; i++) {         
          if (razas[i][0] == id_raza) {
              return razas[i][2];
          }
      }
  }
  
  // The function takes data from the app current state,
  // and insert/links it into the props of our component.
  // This function makes Redux know that this component needs to be passed a piece of the state
  function mapStateToProps(state, props) {
      return {
          loading: state.dataReducer.loading,
          data: state.dataReducer.data
      }
  }
  
  // Doing this merges our actions into the component’s props,
  // while wrapping them in dispatch() so that they immediately dispatch an Action.
  // Just by doing this, we will have access to the actions defined in out actions file (action/home.js)
  function mapDispatchToProps(dispatch) {
      return bindActionCreators(Actions, dispatch);
  }
  
  //Connect everything
  export default connect(mapStateToProps, mapDispatchToProps)(UserPage);
  </code></pre>
  
  <p>However now the problem is that the scrollview is not scrolling....</p>
  
  <p><strong>Edit 2:</strong>
  I resolved this by wrapping all the return() content inside ScrollView.-</p>