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