React Native - VirtualizedList: Sie haben eine große Liste, die nur langsam aktualisiert wird
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 markiertVirtualizedList.getItemLayout, sein Wert ist jedochundefined.
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
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