文章

Flatlist性能调优

术语定义

  • VirtualizedList: FlatList背后的基础支撑组件(是 React Native 对虚拟列表 Virtual List概念的实现)。
  • 内存开销 Memory consumption: 列表在内存中存放多少数据。开销过大可能导致应用崩溃。
  • 响应度 Responsiveness: 应用对于用户操作的响应速度。比如低响应度就是你在操作时,应用要卡一会儿才响应。
  • 空白区 Blank areas:VirtualizedList渲染的速度跟不上你滑动的速度时,你可能会在列表中看到一些尚未完成渲染的空白占位元素。
  • 视口 Viewport: 已渲染内容的可视区域。
  • 滑动窗口 Window: The area in which items should be mounted, which is generally much larger than the viewport.

Props

removeClippedSubviews

类型 DEFAULT
Boolean False

如果为真,在视口之外的视图将从本机视图层次结构中分离。

好处: 启用此选项可减少花在主线程上的时间,从而降低丢帧的风险。原理是对视口之外的视图不进行本地渲染和绘图遍历。

坏处: 请注意,这种实现可能会有 bug,比如丢失内容(主要是在 iOS 上观察到的),特别是当你使用变换和/或绝对定位做复杂的事情时。另外,请注意这并不会节省大量的内存,因为视图并没有被销毁,只是被分离了。

实践:变化不大

推荐指数: ⭐️

maxToRenderPerBatch

类型 DEFAULT
Number 10

它是一个VirtualizedList道具,可以通过FlatList传递。这控制了每批渲染的项目数量,这是每个卷轴上渲染的下一个项目块。

好处: 设置更大的数字意味着滚动时视觉空白区域更少(增加填充率)。

坏处:每批处理的项目越多,意味着JavaScript执行的时间越长,可能会阻塞其他事件处理,比如按下按钮,影响响应。

实践:这是一个取舍问题,取决于你想每次渲染更多的视图还是获得更好的体验

推荐指数: ⭐️ ⭐️

updateCellsBatchingPeriod

类型 DEFAULT
Number 50

maxToRenderPerBatch告诉每个批处理渲染的项目数量,设置updateCellsBatchingPeriod告诉VirtualizedList批处理渲染之间的延迟(以毫秒为单位)(你的组件渲染窗口项目的频率)。

好处:结合这个道具maxToRenderPerBatch给你的权力。例如,少批量呈现更多的条目,或少物品更频繁的批处理。

坏处:少批次可能会引起空白区域,更频繁的批次可能会导致响应问题。

实践:同上

推荐指数: ⭐️ ⭐️

initialNumToRender

类型 DEFAULT
Number 10

要渲染的项目的初始数量。

好处: 为每个设备定义精确的(刚好可以)覆盖屏幕的项目数量。这可以大大提升初始渲染的性能。

坏处:设置一个小的 initialNumToRender 可能导致空白区域,尤其是在初始化渲染的时候,如果设置得太小以至于不能覆盖整个视口。

windowSize

类型 DEFAULT
Number 21

此处传递的数字是一个测量单位,其中 1 等于您的视口高度。 默认值为 21(上方 10 个视口,下方 10 个视口,介于两者之间)。

好处:更大的窗口大小将导致滚动时看到空白空间的机会更少。 另一方面,较小的窗口大小将导致同时安装的项目更少,从而节省内存。

坏处: 对于更大的窗口大小,您将有更多的内存消耗。 对于较低的窗口大小,您将有更大的机会看到空白区域。

List items

使用简单组件

组件越复杂一般渲染就越慢。尽量避免在你的列表项中有很多逻辑和嵌套。如果你在你的应用中经常重用这个列表项组件,为你的大列表创建一个组件,让它们尽可能少的逻辑和嵌套。

推荐指数: ⭐️ ⭐️ ⭐️ ⭐️ (这个没法和产品设计争)

使用轻量组件

组件太重自然也会拖慢渲染。尽量避免使用大图片(优先使用裁剪过的版本或是缩略图,总之越小越好)。和负责

设计的同事协商,在列表中尽可能简化特效和交互,精简要展示的信息,把长内容移到详情页中。

使用 shouldComponentUpdate

对您的组件实施更新验证。 React 的 PureComponent 实现了一个 shouldComponentUpdate 与浅比较。 这在这里很昂贵,因为它需要检查所有道具。 如果您想要良好的位级性能,请为您的列表项组件创建最严格的规则,仅检查可能会更改的道具。 如果您的列表足够简单,您甚至可以使用

1
2
3
shouldComponentUpdate() {
  return false
}

使用优化缓存的图片库

您可以使用来自 @DylanVann 的社区包(例如 react-native-fast-image /DylanVann)) 以获得更高性能的图像。 列表中的每张图片都是一个 new Image() 实例。 它到达 loaded 钩子的速度越快,你的 Javascript 线程就会越快再次空闲。

使用 getItemLayout

如果你所有的列表项组件都有相同的高度(或者宽度,对于水平列表来说),提供getItemLayout prop可以消除 FlatList管理异步布局计算的需要。这是一种非常理想的优化技术。

如果您的组件具有动态大小,并且您确实需要性能,请考虑询问您的设计团队,他们是否可以考虑重新设计以提高性能。

推荐指数: ⭐️ ⭐️ ⭐️ ⭐️

注意:

以下内容摘自React Native FlatList 原理解析与性能优化

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

使用 keyExtractor 或 key

你可以设置 keyExtractor’为你的FlatList组件。该道具用于缓存,并作为React的“关键”来跟踪物品的重新排序。

你也可以在item组件中使用一个“key”属性。

推荐指数: ⭐️ ⭐️ ⭐️ ⭐️

避免在 renderItem 中使用匿名函数

renderItem 函数移出到 render 函数的外部,这样它就不会在每次调用 render 函数时重新创建自己。

推荐指数: ⭐️ ⭐️ ⭐️ ⭐️

参考

本文由作者按照 CC BY 4.0 进行授权