说下React Native FlatList 原理解析与性能优化

1⃣️ 各种列表间的关系

React Native 有好几个列表组件,先简单介绍一下:

  • ScrollView:会把视图里的所有 View 渲染,直接对接 Native 的滚动列表
  • VirtualizedList:虚拟列表核心文件,使用 ScrollView,长列表优化配置项主要是控制它
  • FlatList:使用 VirtualizedList,实现了一行多列的功能,大部分功能都是 VirtualizedList 提供的
  • SectionList:使用 VirtualizedList,底层使用 VirtualizedSectionList,把二维数据转为一维数据

还有一些其他依赖文件,有个🔗 博文的图总结的挺好的,我这里借用它的图一下:

我们可以看出 VirtualizedList 才是主演,下面我们结合一些示例代码,分析它的配置项。

2⃣️ 列表配置项

讲之前先写个小 demo。demo 非常简单,一个基于 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 等概念。

下面是开启 debug 后的 demo 截屏:

上面的图还是很清晰的,右侧 debug 指示条的黄色部分表示内存中 Item,各个属性我们再用文字描述一下:

1.initialNumToRender

首批应该渲染的元素数量,刚刚盖住首屏最好。而且从 debug 指示条可以看出,这批元素会一直存在于内存中。

2.Viewport

视口高度,就是用户能看到内容,一般就是设备高度。

3.windowSize

渲染区域高度,一般为 Viewport 的整数倍。这里我设置为 3,从 debug 指示条可以看出,它的高度是 Viewport 的 3 倍,上面扩展 1 个屏幕高度,下面扩展 1 个屏幕高度。在这个区域里的内容都会保存在内存里。

将 windowSize 设置为一个较小值,能有减小内存消耗并提高性能,但是快速滚动列表时,遇到未渲染的内容的几率会增大,会看到占位的白色 View。大家可以把 windowSize 设为 1 测试一下,100% 会看到占位 View。

4.Blank areas

空白 View,VirtualizedList 会把渲染区域外的 Item 替换为一个空白 View,用来减少长列表的内存占用。顶部和底部都可以有。

上图是渲染图,我们可以利用 react-devtools 再看看 React 的 Virtual DOM(为了截屏方便,我把 initialNumToRender 和 windowSize 设为 1),可以看出和上面的示意图是一致的。

5.removeClippedSubviews

这个翻译过来叫「裁剪子视图」的属性,文档描述不是很清晰,大意是设为 true 可以提高渲染速度,但是 iOS 上可能会出现 bug。这个属性 VirtualizedList 没有做任何优化,是直接透传给 ScrollView 的。

在 0.59 版本的一次 🔗 commit 里,FlatList 默认 Android 开启此功能,如果你的版本低于 0.59,可以用以下方式开启:

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

6.maxToRenderPerBatch 和 updateCellsBatchingPeriod

VirtualizedList 的数据不是一下子全部渲染的,而是分批次渲染的。这两个属性就是控制增量渲染的。

这两个属性一般是配合着用的,maxToRenderPerBatch 表示每次增量渲染的最大数量,updateCellsBatchingPeriod 表示每次增量渲染的时间间隔

我们可以调节这两个参数来平衡渲染速度和响应速度。但是,调参作为一门玄学,很难得出一个统一的「最佳实践」,所以我们在业务中也没有动过这两个属性,直接用的系统默认值。

2⃣️ ListLtems 优化

📄 ListLtems 优化 文档https://reactnative.cn/docs/optimizing-flatlist-configuration/#list-items

文档中说了好几点优化,其实在前文我都介绍过了,这里再简单提一下:

1.使用 getItemLayout

如果 FlatList(VirtualizedList)的 ListLtem 高度是固定的,那么使用 getItemLayout 就非常的合算。

在源码中(#L1287#L2046),如果不使用 getItemLayout,那么所有的 Cell 的高度,都要调用 View 的 onLayout 动态计算高度,这个运算是需要消耗时间的;如果我们使用了 getItemLayout,VirtualizedList 就直接知道了 Cell 的高度和偏移量,省去了计算,节省了这部分的开销。

在这里我还想提一下几个注意点,希望大家使用 getItemLayout 要多注意一下:

  • 如果 ListItem 高度不固定,使用 getItemLayout 返回固定高度时,因为最终渲染高度和预测高度不一致,会出现页面跳动的问题
  • 如果使用了 ItemSeparatorComponent,分隔线的尺寸也要考虑到 offset 的计算中
  • 如果 FlatList 使用的时候使用了 ListHeaderComponent,也要把 Header 的尺寸考虑到 offset 的计算中

2.Use simple components & Use light components

使用简单组件,核心就是减少逻辑判断和嵌套,优化方式可以参考「二、减轻渲染压力」的内容。

3.Use shouldComponentUpdate

参考「一、re-render」的内容。

4.Use cached optimized images

参考「三、图片优化那些事」的内容。

5.Use keyExtractor or key

常规优化点了,可以看 React 的文档 🔗 列表 & Key

6.Avoid anonymous function on renderItem

renderItem 避免使用匿名函数,参考「四、对象创建调用分离」的内容。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Native 是一种基于 React 的跨平台移动应用开发框架,其性能受到多种因素的影响。以下是一些优化 React Native 应用性能的建议: 1. 减少渲染次数。React Native 的渲染是基于虚拟 DOM 的,因此组件的更新会引起重新渲染。减少组件的更新次数可以减少渲染次数。可以使用 shouldComponentUpdate 或 PureComponent 来避免不必要的渲染。 2. 使用 FlatList 或 SectionListFlatList 和 SectionListReact Native 的内置组件,它们可以帮助减少渲染次数和内存使用。它们可以按需渲染列表项,而不是一次性渲染所有列表项。 3. 使用动画。React Native 提供了一些内置的动画组件和 API,可以让应用的界面更加流畅和生动。使用动画时,应尽量避免在渲染期间执行操作,以免影响性能。 4. 使用原生组件。React Native 允许开发者使用原生组件来替代一些 React Native 内置组件,以提高性能。例如,使用原生 ScrollView 替代 React Native 的 ScrollView。 5. 使用性能监测工具。React Native 提供了一些性能监测工具,例如 React Native Performance MonitorReactotron,可以帮助开发者分析应用的性能瓶颈,从而进行针对性的优化。 6. 使用代码分割。React Native 应用可以使用代码分割来减少应用的首次加载时间。可以使用 React Native 的内置代码分割工具或第三方工具进行代码分割。 7. 使用缓存。React Native 应用可以使用缓存技术来减少网络请求和数据处理的次数,从而提高应用的性能。可以使用内置的 AsyncStorage 或第三方缓存库来实现缓存。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值