React Native - VirtualizedList: Sie haben eine große Liste, die nur langsam aktualisiert wird

Sep 13 2020

Einführung

Ich habe ernsthafte Leistungsprobleme mit meiner VirtualizedList (unendlicher Bildlauf) ... Ich habe dies verfolgt , um es zu verbessern, arbeite aber immer noch sehr langsam.

Wenn ich nach unten scrolle, gehen die UI-Threads von 60 fps auf 30 fps und der JS-Thread von 60 fps auf 10/20 fps (manchmal auf 0 fps). Unter iOS (iPhone 6) scheint es reibungslos zu laufen als auf meinem Android (Samsung Galaxy S8 +)

Meine VirtualizedList rendert Elemente mit unterschiedlichen Höhen und ruft die Daten ab, wenn das Ende erreicht ist. Mein Artikel erstreckt sich von React.PureComponent, wie empfohlen:

VirtualizedList: Sie haben eine große Liste, die nur langsam aktualisiert wird. Stellen Sie sicher, dass Ihre renderItem-Funktion Komponenten rendert, die den Best Practices für die React-Leistung entsprechen, z. B. PureComponent, shouldComponentUpdate usw. Object {"contentLength": 20720, "dt": 532, "prevDt" : 2933,}

Dieses Problem tritt auf, wenn ich ungefähr 20 Elemente nach unten scrolle ...

Code

Hier ist der Code der VirtualizedList:

const keyExtractor = ({ id }) => id;
...
 
getItem = (data, index) => data[index];

getItemCount = (data) => data.length;

renderItem = ({ item, index }) => {
 const {
   images,
   dimensions,
   description,
   location,
   likes,
   comments,
   date,
 } = item;

 return (
   <Card
     images={images}
     postDimensions={dimensions}
     description={description}
     location={location}
     likes={likes}
     comments={comments}
     date={date}
   />
 );
};

<VirtualizedList
    data={data}
    getItem={this.getItem}
    getItemCount={this.getItemCount}
    keyExtractor={keyExtractor}
    listKey={listKey}
    legacyImplementation={false}
    numColumns={1}
    renderItem={this.renderItem}
    initialNumToRender={MAX_POSTS_TO_RETRIEVE_LENGTH} // 10
    windowSize={32}
    maxToRenderPerBatch={15}
    updateCellsBatchingPeriod={50}
    removeClippedSubviews={false}
    ListFooterComponent={this.renderFooter}
    ListEmptyComponent={ListEmptyComponent}
    onEndReached={onEndReached}
    onEndReachedThreshold={0.5}
/>

Pd: Jedes Element, das ich rendere, hat eine eindeutige ID.

Was ich versucht habe

Ich habe versucht, meine eigene getItemLayout-Methode für die Liste zu implementieren, aber aus irgendeinem Grund funktioniert sie nicht richtig.

Warnung: Fehlgeschlagener Rahmentyp: Der Rahmen frame.lengthist als erforderlich markiert VirtualizedList.getItemLayout, sein Wert ist jedoch undefined.

itemHeights = [];

getItemLayout = (data, index) => {
  const length = this.itemHeights[index];
  const offset = this.itemHeights.slice(0,index).reduce((a, c) => a + c, 0)
  return {length, offset, index}
}

renderItem = ({ item, index }) => {
 const {
   images,
   dimensions,
   description,
   location,
   likes,
   comments,
   date,
 } = item;

 return (
   <View onLayout={(event) => this.itemHeights[index] = event.nativeEvent.layout.height}>
    <Card
      images={images}
      postDimensions={dimensions}
      description={description}
      location={location}
      likes={likes}
      comments={comments}
      date={date}
    />
   </View>
 );
};

<VirtualizedList
    data={data}
    getItem={this.getItem}
    getItemCount={this.getItemCount}
    getItemLayout={this.getItemLayout}
    keyExtractor={keyExtractor}
    listKey={listKey}
    legacyImplementation={false}
    numColumns={1}
    renderItem={this.renderItem}
    initialNumToRender={MAX_POSTS_TO_RETRIEVE_LENGTH} // 10
    windowSize={32}
    maxToRenderPerBatch={15}
    updateCellsBatchingPeriod={50}
    removeClippedSubviews={false}
    ListFooterComponent={this.renderFooter}
    ListEmptyComponent={ListEmptyComponent}
    onEndReached={onEndReached}
    onEndReachedThreshold={0.5}
/>

Irgendwelche Ideen? Ich habe gesehen, dass es ein häufiges Problem ist, aber ich habe keine Lösung gefunden.

AKTUALISIEREN

Um das Problem mit getItemLayout zu lösen, gehen Sie einfach wie folgt vor:

getItemLayout = (data, index) => {
  const length = this.itemHeights[index] || 0; // <----- if undefined return 0
  const offset = this.itemHeights.slice(0,index).reduce((a, c) => a + c, 0)
  return {length, offset, index}
}

Antworten

VictorMolina Sep 14 2020 at 04:45

Wenn dies jemandem passiert, verwenden Sie einfach meine benutzerdefinierte Funktion getItemLayout und befolgen Sie diese Schritte

Die Verwendung dieser Werte hat bei mir funktioniert.

    initialNumToRender={10}
    windowSize={5}
    maxToRenderPerBatch={5}
    updateCellsBatchingPeriod={30}
    removeClippedSubviews={false}
    ...
    onEndReachedThreshold={0.1}

Pd: Mein Ansichtsfenster ist mit 1,5 Elementen bedeckt