utilizzando React.memo nel componente funzionale per renderItem FlatList per ridurre al minimo il re-rendering degli elementi esistenti

Aug 20 2020

Sto usando componenti funzionali e sto usando Flatlist per rendere l'elenco dei dati, funziona bene, ma ogni volta che lo stato ottiene dati aggiuntivi viene sempre ri-renderizzato esistente e causerà problemi di prestazioni, ho letto questi articoli da SO ma ha ancora nessun indizio

  • https://stackoverflow.com/a/57405307/938947
  • https://stackoverflow.com/a/46349156/938947

ecco il mio codice che utilizza main Flatlist

<FlatList
  horizontal={false}
  showsHorizontalScrollIndicator={false}
  data={users}
  keyExtractor={(item, index) => String(index)}
  renderItem={RenderUser}
  onEndReachedThreshold={0.7}
  onEndReached={callBackMoreData}
/>

e qui funziona RenderUser ma il problema è il rendering dell'elemento esistente se lo stato ha dati aggiuntivi, quello che vorrei ottenere è solo il rendering di dati aggiuntivi

import React from 'react';
import { ListItem } from 'react-native-elements';

const RenderUser = ({ item, index }) => {

  return (
    <React.Fragment>
      { console.log('index: ', index)}
      <ListItem 
        title={item.attributes.name}
      />
    </React.Fragment>
  );
};

export default RenderUser;

e ho provato a utilizzare questo codice di seguito (ma ricevo un messaggio di errore che dice TypeError: renderItem non è una funzione. (in 'renderItem(props)', 'renderItem' è un'istanza di oggetto))

import React, { memo } from 'react';
import { ListItem } from 'react-native-elements';

const RenderUser = ({ item, index }) => {

  return (
    <React.Fragment>
      { console.log('index: ', index)}
      <ListItem 
        title={item.attributes.name}
      />
    </React.Fragment>
  );
};

export default memo(RenderUser);

Risposte

2 ShubhamVerma Aug 20 2020 at 15:18

Secondo reagire documentazione ufficiale:

Per impostazione predefinita, confronterà solo superficialmente oggetti complessi nell'oggetto props. Se vuoi controllare il confronto, puoi anche fornire una funzione di confronto personalizzata come secondo argomento

function MyComponent(props) {
  /* render using props */
}
function areEqual(prevProps, nextProps) {
  /*
  return true if passing nextProps to render would return
  the same result as passing prevProps to render,
  otherwise return false
  */
}
export default React.memo(MyComponent, areEqual);

Nel tuo caso devi aggiungere la condizione:

import React, { memo } from 'react';
import { ListItem } from 'react-native-elements';

const RenderUser = ({ item, index }) => {

  return (
    <React.Fragment>
      { console.log('index: ', index)}
      <ListItem 
        title={item.attributes.name}
      />
    </React.Fragment>
  );
};

function arePropsEqual(prevProps, nextProps) {
      /*
      return true if passing nextProps to render would return
      the same result as passing prevProps to render,
      otherwise return false
      */
      return nextProps.item.attribute.name===prevProps.item.attribute.name
    }

export default memo(RenderUser,arePropsEqual);

Nota : non sono sicuro di quanti oggetti di scena stai ricevendo e quali sono unici. Fondamentalmente devi confrontare che l'ultimo è uguale a questo restituisce true in questo modo la reazione non riproduce nuovamente il tuo componente