React Native - VirtualizedList: Bạn có một danh sách lớn cập nhật chậm

Sep 13 2020

Giới thiệu

Tôi đang gặp vấn đề nghiêm trọng về hiệu suất với VirtualizedList (cuộn vô hạn) ... Tôi đã làm theo cách này để cải thiện nó nhưng vẫn hoạt động rất chậm.

Khi tôi cuộn xuống, các chuỗi giao diện người dùng đi từ 60fps đến 30fps và chuỗi JS từ 60fps đến 10 / 20fps (đôi khi đến 0fps). Trên iOS (iPhone 6) có vẻ suôn sẻ hơn trên Android của tôi (Samsung Galaxy S8 +)

VirtualizedList của tôi đang hiển thị các mục có độ cao khác nhau và nó tìm nạp dữ liệu khi đạt đến cuối của nó. Mục của tôi mở rộng từ React.PureComponent, vì nó được khuyến nghị:

VirtualizedList: Bạn có một danh sách lớn cập nhật chậm - hãy đảm bảo rằng hàm renderItem của bạn hiển thị các thành phần tuân theo các phương pháp hay nhất về hiệu suất React như PureComponent, shouldComponentUpdate, v.v. Đối tượng {"contentLength": 20720, "dt": 532, "presDt" : 2933,}

Sự cố này xảy ra khi tôi cuộn xuống khoảng 20 mục ...

Mã

Đây là mã của 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: mỗi mục tôi đang hiển thị có một id duy nhất.

Những gì tôi đã thử

Tôi đã cố gắng triển khai phương thức getItemLayout của riêng mình cho Danh sách nhưng vì một số lý do, nó không hoạt động bình thường.

Cảnh báo: Loại khung không thành công: Khung frame.lengthđược đánh dấu là bắt buộc trong VirtualizedList.getItemLayout, nhưng giá trị của nó là 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}
/>

Bất kỳ ý tưởng? Tôi đã thấy rằng đó là một vấn đề phổ biến nhưng tôi đã không tìm thấy bất kỳ giải pháp.

CẬP NHẬT

Để giải quyết vấn đề tôi gặp phải với getItemLayout, chỉ cần làm:

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}
}

Trả lời

VictorMolina Sep 14 2020 at 04:45

Nếu điều này xảy ra với ai đó, chỉ cần sử dụng hàm getItemLayout tùy chỉnh của tôi và làm theo các bước sau

Sử dụng những giá trị đó đã làm việc cho tôi.

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

Pd: khung nhìn của tôi được bao phủ bởi 1,5 mục