【问题标题】:FlatList renderItem is called multiple timesFlatList renderItem 被多次调用
【发布时间】:2018-07-16 16:01:17
【问题描述】:

我正在使用 FlatList 显示来自 API 调用的数据:

render() {
  const { navigation } = this.props;
  const animating = this.state.animating;

  return (
    <View style={styles.container}>
      <ActivityIndicator
        animating = {animating}
        color = '#E3A141'
        size = {120}
        style = {styles.activityIndicator}
      /> 
      <FlatList                    
        ref='listRef'
        data={this.props.data}
        renderItem={this.renderItem}
        keyExtractor={(item, index) => index.toString()}
      />   
      <SocialFooter navigation={navigation}/>
    </View>
  )
}

renderItem({item, index}) {
  console.log("renderItem(item): ", item, "index: ", index)
}

返回的数据是一个包含 3 个对象和一个数组的数组,正如您在输出中看到的那样,renderItem() 对数组中的每个对象调用一次:

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

这是获取调用:

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) => response.json())
    .then((responseJson) => {
      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) => {
      console.error(error);
    });
}

我发现了很多类似的帖子,他们说这是一个反应原生错误,我该怎么办?。谢谢

编辑:

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 ( 
                <View>
                    <View style={styles.header_container}>
                        <Image source={require('./img/logo-mini.png')} style={styles.logo_img} />
                        <Link to="/" style={styles.back_link} underlayColor="#f0f4f7">
                            <Image  
                                source={require("./img/back.png")}
                                style={styles.back_img}
                            />
                        </Link>
                    </View>
                    <View style={styles.container_credential}>
                        <Image source={require('./img/base-face-image.png')} style={styles.customer_img} />
                        <View style={styles.credential_details}>
                            <Text style={styles.customer_fullName}>
                                {datosSocio.titular} 
                            </Text>
                            <Text style={styles.customer_member_id}>
                                Socio ID: {datosSocio.socioID}                         
                            </Text>
                            <Text style={styles.customer_dni}>
                                DNI: {datosSocio.dni}                
                            </Text>
                            <Text style={styles.credential_notice_title}>
                                ¡IMPORTANTE! 
                            </Text>
                            <Text style={styles.credential_notice_content}>
                                El uso de esta credencial debe ser acompañado por el DNI del titular.
                            </Text>
                        </View>
                    </View>
                    <View style={styles.container_mascotas_list_title}> 
                        <Text style={styles.mascotas_list_title_text_first}>Mis</Text><Text style={styles.mascotas_list_title_text_last}> mascotas:</Text>                    
                    </View>
                    <View style={styles.mascotas_list_title_underline}></View>
                    <ScrollView>          
                        {this.props.data.map(mascota => {
                            return ( 
                            <View key={mascota.nombre}>

                                    <Text style={styles.mascotas_list_item_details_name}>Nombre: {mascota.nombre}</Text>                                    
                                    <Text style={styles.mascotas_list_item_details_name}>Raza: {getRaza(mascota.raza)}</Text>
                                    <Text style={styles.mascotas_list_item_details_name}>Especie: {getEspecie(mascota.raza)}</Text>
                                    <Text style={styles.mascotas_list_item_details_sex_hair}>Sexo: {mascota.sexo}</Text>
                                    <Text style={styles.mascotas_list_item_details_sex_hair}>Color pelo: {mascota.color}</Text>

                            </View>
                            );
                        })}
                    </ScrollView>
                </View>
          );
        } else {
          return null;
        }
      }
};

function getRaza(id_raza) {
    for (let i = 0; i < razas.length; i++) {
        if (razas[i][0] == id_raza) {
            return razas[i][1];
        }
    }
}

function getEspecie(id_raza) {
    for (let i = 0; i < 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);

但是现在的问题是滚动视图没有滚动......

编辑 2: 我通过将所有 return() 内容包装在 ScrollView 中解决了这个问题。-

【问题讨论】:

  • renderItem 为每个项目呈现。这是 FlatList 的预期行为。我不确定你遇到了什么问题。
  • 问题是返回的视图每次都显示数组中的对象,我需要获取该数据并循环它,以便我可以在列表中显示 1 个视图。
  • @bennygenel 我清楚这个问题吗?谢谢。
  • "我通过将所有 return() 内容包装在 ScrollView 中解决了这个问题。"

标签: javascript react-native redux react-native-flatlist


【解决方案1】:

正常的重新渲染在 RN 中是正常的。那只是 RN 更新反应树和更新视图。如果您没有性能问题,那么您可以忽略这一点。

否则,请解释问题,因为控制台日志很好。为您传递给 FlatList 的数据数组中的每个项目执行渲染项目。这是每个项目的渲染功能,而不是整个列表的渲染。

如果这还不够清楚,并且对您来说更容易,请随时在此处添加西班牙语评论,然后我们可以更新答案(仅说这是因为您的用户,您像我一样缝制西班牙语)

【讨论】:

  • 根据我的经验,即使组件只执行一个渲染周期,renderItem 也会莫名其妙地被调用多次。
【解决方案2】:

https://snack.expo.io/B1KoX-EUN - 为了优化和防止重新渲染,您可以调用 shouldComponentUpdate(nextProps, nextState) 来区分 this.state 或 this.props 并返回 true/false - https://reactjs.org/docs/react-component.html#shouldcomponentupdate 文档说这个回调应该只用于这就是我们在这里所做的优化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-04
    • 1970-01-01
    相关资源
    最近更新 更多