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 函数时重新创建自己。
推荐指数: ⭐️ ⭐️ ⭐️ ⭐️