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