优化 FlatList 配置
术语
-
VirtualizedList:
FlatList
背后的组件(React Native 对Virtual List
概念的实现)。 -
内存消耗:列表中有多少信息存储在内存中,这可能导致应用崩溃。
-
响应能力:应用程序响应交互的能力。例如,低响应能力是指当您点击某个组件时,它会等待一段时间才能响应,而不是像预期的那样立即响应。
-
空白区域:当
VirtualizedList
无法足够快地渲染项目时,您可能会进入列表的一部分,其中未渲染的组件显示为空白空间。 -
视口:渲染到像素的内容的可视区域。
-
窗口:项目应挂载的区域,通常比视口大得多。
属性
以下是一些有助于提高 FlatList
性能的属性
removeClippedSubviews
类型 | 默认值 |
---|---|
布尔值 | false |
如果 true
,则视口外的视图将从原生视图层次结构中分离。
优点:这减少了在主线程上花费的时间,从而通过将视口外的视图排除在原生渲染和绘制遍历之外来降低出现丢帧的风险。
缺点:请注意,此实现可能存在错误,例如内容丢失(主要在 iOS 上观察到),尤其是在您使用变换和/或绝对定位执行复杂操作时。另请注意,这不会节省大量内存,因为视图不会被释放,只会分离。
maxToRenderPerBatch
类型 | 默认值 |
---|---|
数字 | 10 |
这是一个可以通过 FlatList
传递的 VirtualizedList
属性。它控制每次批处理渲染的项目数量,也就是每次滚动时渲染的下一块项目。
优点:设置更大的数字意味着在滚动时视觉空白区域更少(提高填充率)。
缺点:每个批次更多的项目意味着更长的 JavaScript 执行时间,可能会阻塞其他事件处理(如按下),从而损害响应能力。
updateCellsBatchingPeriod
类型 | 默认值 |
---|---|
数字 | 50 |
虽然 maxToRenderPerBatch
指示每个批次渲染的项目数量,但设置 updateCellsBatchingPeriod
会告诉您的 VirtualizedList
批次渲染之间的延迟(以毫秒为单位)(您的组件渲染窗口化项目的频率)。
优点:将此属性与 maxToRenderPerBatch
结合使用,您可以例如以较低的频率渲染更多项目,或以较高的频率渲染较少的项目。
缺点:较低的批次频率可能会导致出现空白区域,较高的批次频率可能会导致响应能力问题。
initialNumToRender
类型 | 默认值 |
---|---|
数字 | 10 |
要渲染的初始项目数量。
优点:为每个设备定义覆盖屏幕的精确项目数量。这可以极大地提高初始渲染的性能。
缺点:设置较低的 initialNumToRender
可能会导致出现空白区域,尤其是在初始渲染时它太小而无法覆盖视口。
windowSize
类型 | 默认值 |
---|---|
数字 | 21 |
此处传递的数字是一个度量单位,其中 1 等于视口高度。默认值为 21(上方 10 个视口,下方 10 个视口,中间 1 个)。
优点:更大的 windowSize
将导致更少的机会看到滚动时的空白空间。另一方面,较小的 windowSize
将导致同时挂载的项目更少,从而节省内存。
缺点:对于更大的 windowSize
,您将有更多的内存消耗。对于较低的 windowSize
,您将更有可能看到空白区域。
列表项
以下是关于列表项组件的一些提示。它们是列表的核心,因此它们需要快速。
使用基本组件
组件越复杂,渲染速度越慢。尝试避免在列表项中使用过多的逻辑和嵌套。如果您在应用程序中大量重用此列表项组件,请仅为大型列表创建一个组件,并使它们尽可能少地包含逻辑和嵌套。
使用轻量级组件
组件越重,渲染速度越慢。避免使用重量级图像(对于列表项,请使用裁剪版本或缩略图,尽可能小)。与您的设计团队沟通,在列表中尽可能少地使用效果、交互和信息。在项目的详细信息中显示它们。
使用 memo()
React.memo()
创建一个记忆化组件,该组件仅在传递给组件的属性发生更改时才会重新渲染。我们可以使用此函数来优化 FlatList 中的组件。
import React, {memo} from 'react';
import {View, Text} from 'react-native';
const MyListItem = memo(
({title}: {title: string}) => (
<View>
<Text>{title}</Text>
</View>
),
(prevProps, nextProps) => {
return prevProps.title === nextProps.title;
},
);
export default MyListItem;
在此示例中,我们已确定 MyListItem 仅在标题更改时才应重新渲染。我们将比较函数作为第二个参数传递给 React.memo(),以便仅在指定属性更改时才重新渲染组件。如果比较函数返回 true,则不会重新渲染组件。
使用缓存优化后的图像
您可以使用社区软件包(例如来自@DylanVann 的react-native-fast-image)来获得更高性能的图像。列表中的每个图像都是一个 new Image()
实例。它越快到达 loaded
钩子,JavaScript 线程就会越快再次释放。
使用 getItemLayout
如果所有列表项组件都具有相同的高度(或宽度,对于水平列表),则提供 getItemLayout 属性可以避免 FlatList
管理异步布局计算。这是一种非常理想的优化技术。
如果您的组件具有动态大小并且您确实需要性能,请考虑询问您的设计团队他们是否可以考虑重新设计以获得更好的性能。
使用 keyExtractor 或 key
您可以将 keyExtractor
设置为您的 FlatList
组件。此属性用于缓存并作为 React key
来跟踪项目的重新排序。
您也可以在项目组件中使用 key
属性。
避免在 renderItem 上使用匿名函数
对于函数式组件,请将 renderItem
函数移到返回的 JSX 之外。此外,请确保它被 useCallback
钩子包裹,以防止它在每次渲染时都被重新创建。
对于类组件,请将 renderItem
函数移到 render 函数之外,这样它就不会在每次调用 render 函数时都重新创建自己。
const renderItem = useCallback(({item}) => (
<View key={item.key}>
<Text>{item.title}</Text>
</View>
), []);
return (
// ...
<FlatList data={items} renderItem={renderItem} />;
// ...
);