React Native - VirtualizedList:您有一个更新缓慢的列表

Vic*_*ina 2 javascript reactjs react-native

介绍

我的 VirtualizedList (无限滚动)遇到严重的性能问题...我一直在遵循此方法来改进它,但仍然工作得很慢。

当我向下滚动时,UI 线程从 60fps 变为 30fps,JS 线程从 60fps 变为 10/20fps(有时变为 0fps)。在 iOS (iPhone 6) 上似乎比在我的 Android (Samsung Galaxy S8+) 上运行流畅

我的 VirtualizedList 正在渲染具有不同高度的项目,并在到达末尾时获取数据。我的项目从 React.PureComponent 扩展而来,正如推荐的那样:

VirtualizedList:您有一个更新缓慢的列表 - 确保您的 renderItem 函数渲染遵循 React 性能最佳实践的组件,例如 PureComponent、shouldComponentUpdate 等。 Object { "contentLength": 20720, "dt": 532, "prevDt" :2933,}

当我向下滚动大约 20 个项目时,就会出现这个问题......

代码

这是 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}
/>
Run Code Online (Sandbox Code Playgroud)

Pd:我渲染的每个项目都有一个唯一的 ID。

我尝试过的

我尝试为列表实现我自己的 getItemLayout 方法,但由于某种原因它无法正常工作。

警告:失败的帧类型:该帧frame.length按照 中的要求进行标记VirtualizedList.getItemLayout,但其值为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}
/>
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?我发现这是一个常见问题,但我还没有找到任何解决方案。

更新

要解决我在 getItemLayout 中遇到的问题,只需执行以下操作:

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}
}
Run Code Online (Sandbox Code Playgroud)

Vic*_*ina 6

如果有人遇到这种情况,只需使用我的自定义 getItemLayout 函数并按照以下步骤操作

使用这些价值观对我来说很有效。

    initialNumToRender={10}
    windowSize={5}
    maxToRenderPerBatch={5}
    updateCellsBatchingPeriod={30}
    removeClippedSubviews={false}
    ...
    onEndReachedThreshold={0.1}
Run Code Online (Sandbox Code Playgroud)

Pd:我的视口被 1.5 个项目覆盖