React Native 列表性能优化配置详解

Viewed 0

在 React Native 开发中,长列表的性能优化是一个常见且重要的场景。优化得当,即使渲染千条数据也能保持流畅。虚拟列表的核心思想是只渲染当前和即将展示的视图,用空白视图替代远处元素,以减少内存占用。

React Native 官网提供了列表配置优化的指南,但理解这些配置项需要深入。本文将详细解释这些配置,帮助开发者更好地理解和应用。

各种列表间的关系

React Native 提供了多个列表组件,简单介绍如下:

  • ScrollView:渲染所有子视图,直接对应原生滚动列表。
  • VirtualizedList:虚拟列表的核心组件,基于 ScrollView,主要优化配置项都用于控制它。
  • FlatList:使用 VirtualizedList,支持一行多列布局,大部分功能源自 VirtualizedList。
  • SectionList:使用 VirtualizedList,通过 VirtualizedSectionList 将二维数据转换为一维数据进行渲染。

VirtualizedList 是这些列表组件的核心,下面结合示例代码分析其关键配置项。

列表配置项

首先,通过一个简单的 FlatList 示例来演示配置项的作用。该示例创建一个奇偶行颜色不同的列表:

export default class App extends React.Component {
  renderItem = item => {
    return (
      <Text
        style={{
          backgroundColor: item.index % 2 === 0 ? 'green' : 'blue',
        }}>
        {'第 ' + (item.index + 1) + ' 个'}
      </Text>
    );
  }

  render() {
    let data = [];
    for (let i = 0; i < 1000; i++) {
      data.push({key: i});
    }

    return (
      <View style={{flex: 1}}>
        <FlatList
          data={data}
          renderItem={this.renderItem}
          initialNumToRender={3} // 首批渲染的元素数量
          windowSize={3} // 渲染区域高度
          removeClippedSubviews={Platform.OS === 'android'} // 是否裁剪子视图
          maxToRenderPerBatch={10} // 增量渲染最大数量
          updateCellsBatchingPeriod={50} // 增量渲染时间间隔
          debug // 开启 debug 模式
        />
      </View>
    );
  }
}

VirtualizedList 支持一个未在文档中明确说明的 debug 配置项,开启后会在视图右侧显示虚拟列表的调试信息,帮助直观理解 initialNumToRender、windowSize、Viewport 和 Blank areas 等概念。

1. initialNumToRender

首批应该渲染的元素数量,建议设置为刚好覆盖首屏。调试信息显示,这些元素会一直保留在内存中。

2. Viewport

视口高度,即用户当前可见的内容区域,通常等于设备屏幕高度。

3. windowSize

渲染区域高度,一般为 Viewport 的整数倍。例如,设置为 3 时,渲染区域高度是 Viewport 的 3 倍,向上和向下各扩展一个屏幕高度,该区域内的所有内容都会保存在内存中。减小 windowSize 可以降低内存消耗并提升性能,但快速滚动时遇到未渲染内容的几率会增加,导致出现空白占位视图。将 windowSize 设为 1 进行测试,会 100% 看到占位视图。

4. Blank areas

空白视图,VirtualizedList 会将渲染区域外的列表项替换为空白视图,以减少长列表的内存占用。空白区域可能出现在列表的顶部或底部。

5. removeClippedSubviews

“裁剪子视图”属性,文档描述较为模糊,大致意思是设置为 true 可以提高渲染速度,但在 iOS 上可能出现 Bug。此属性由 VirtualizedList 直接透传给底层的 ScrollView,未做额外优化。

在 React Native 0.59 版本的一次提交中,FlatList 默认在 Android 平台上开启了此功能。如果版本低于 0.59,可以通过以下方式手动开启:

removeClippedSubviews={Platform.OS === 'android'}

6. maxToRenderPerBatch 和 updateCellsBatchingPeriod

VirtualizedList 采用增量渲染方式,数据会分批进行渲染。这两个属性共同控制增量渲染行为:maxToRenderPerBatch 定义每次增量渲染的最大数量,updateCellsBatchingPeriod 定义每次增量渲染的时间间隔。调整这两个参数可以在渲染速度和响应速度之间取得平衡,但由于调参的复杂性,通常建议直接使用系统默认值,除非有明确的性能瓶颈需要优化。

ListItems 优化

参考官方文档,针对列表项的优化主要包括以下几点:

1. 使用 getItemLayout

如果 FlatList 或 VirtualizedList 的列表项高度固定,使用 getItemLayout 属性可以显著提升性能。因为不使用此属性时,每个单元格的高度都需要通过 View 的 onLayout 回调动态计算,消耗时间;使用后,VirtualizedList 直接知晓单元格的高度和偏移量,省去了计算开销。

注意事项:

  • 列表项高度不固定时,使用 getItemLayout 返回固定高度可能导致最终渲染高度与预测不一致,引起页面跳动。
  • 如果使用了 ItemSeparatorComponent,分隔线的尺寸必须计入偏移量计算。
  • 如果使用了 ListHeaderComponent,Header 的尺寸也需要考虑在偏移量计算中。

2. 使用简单组件和轻量组件

核心是减少组件内部的逻辑判断和嵌套层次,具体优化方式可参考减轻渲染压力的相关实践。

3. 使用 shouldComponentUpdate

通过实现 shouldComponentUpdate 生命周期方法避免不必要的重渲染,具体参考 re-render 优化的内容。

4. 使用缓存优化图片

对于列表中的图片,采用缓存和优化策略,具体参考图片优化的内容。

5. 为列表项设置唯一 key

这是 React 列表渲染的常规优化点,确保每个列表项具有稳定且唯一的 key 值,以提升 diff 效率。

6. 避免在 renderItem 中使用匿名函数

renderItem 属性中避免使用匿名函数,以减少不必要的函数创建,具体参考对象创建调用分离的优化内容。

通过合理配置上述选项并遵循优化建议,可以显著提升 React Native 长列表的性能和用户体验。

0 Answers