跳到主要内容

优化 Flatlist 配置

术语

  • VirtualizedList: FlatList 背后的组件(React Native 对 虚拟列表 概念的实现。)

  • 内存消耗: 列表中有多少信息被存储在内存中,这可能导致应用程序崩溃。

  • 响应性: 应用程序响应交互的能力。例如,低响应性是指您触摸组件后,它会等待一段时间才响应,而不是像预期的那样立即响应。

  • 空白区域:VirtualizedList 无法足够快地渲染项目时,您可能会进入列表的某个部分,其中包含未渲染的组件,这些组件显示为空白区域。

  • 视口: 渲染到像素的内容的可见区域。

  • 窗口: 应该挂载项目的区域,通常比视口大得多。

Props

以下是一些可以帮助提高 FlatList 性能的 props

removeClippedSubviews

类型默认值
布尔值False

如果为 true,则视口外的视图将从原生视图层级中分离。

优点: 这减少了在主线程上花费的时间,从而通过将视口外的视图排除在原生渲染和绘制遍历之外,降低了丢帧的风险。

缺点: 请注意,此实现可能存在错误,例如内容丢失(主要在 iOS 上观察到),特别是当您对变换和/或绝对定位执行复杂操作时。另请注意,这不会节省大量内存,因为视图不会被释放,只是分离了。

maxToRenderPerBatch

类型默认值
数字10

这是一个 VirtualizedList prop,可以传递给 FlatList。它控制每次渲染批次的数量,即每次滚动时渲染的下一块项目。

优点: 设置较大的数字意味着滚动时视觉空白区域更少(提高填充率)。

缺点: 每批次项目越多意味着 JavaScript 执行时间越长,可能会阻塞其他事件处理,例如按下操作,从而影响响应性。

updateCellsBatchingPeriod

类型默认值
数字50

虽然 maxToRenderPerBatch 指定了每批次渲染的项目数量,但设置 updateCellsBatchingPeriod 则告诉您的 VirtualizedList 批次渲染之间的延迟(以毫秒为单位)(组件渲染窗口化项目的频率)。

优点: 将此 prop 与 maxToRenderPerBatch 结合使用,您可以灵活地例如在频率较低的批次中渲染更多项目,或在频率较高的批次中渲染更少项目。

缺点: 较低频率的批次可能会导致空白区域,较高频率的批次可能会导致响应性问题。

initialNumToRender

类型默认值
数字10

初始渲染的项目数量。

优点: 为每种设备定义可以覆盖屏幕的精确项目数量。这可以大大提升初始渲染的性能。

缺点: 设置较低的 initialNumToRender 可能会导致空白区域,尤其是在初始渲染时它太小而无法覆盖视口的情况下。

windowSize

类型默认值
数字21

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

优点: 更大的 windowSize 将减少滚动时看到空白区域的机会。另一方面,更小的 windowSize 将导致同时挂载的项目更少,从而节省内存。

缺点: 对于更大的 windowSize,您将消耗更多内存。对于更小的 windowSize,您将有更大的机会看到空白区域。

列表项

以下是一些关于列表项组件的提示。它们是列表的核心,因此需要快速。

使用基础组件

组件越复杂,渲染速度就越慢。尽量避免在列表项中包含大量逻辑和嵌套。如果您在应用中大量重复使用此列表项组件,请仅为大型列表创建一个组件,并使其尽可能少包含逻辑和嵌套。

使用轻量组件

组件越重,渲染速度就越慢。避免使用大型图片(为列表项使用裁剪版本或缩略图,尽可能小)。与您的设计团队沟通,在列表中尽可能少使用效果、交互和信息。在项目的详情中展示它们。

使用 memo()

React.memo() 创建一个记忆化组件,只有当传递给组件的 props 发生变化时才会重新渲染。我们可以使用此函数来优化 FlatList 中的组件。

tsx
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,则组件将不会重新渲染。

使用缓存的优化图片

您可以使用社区包(例如来自 @DylanVannreact-native-fast-image)来获得更高性能的图片。列表中的每张图片都是一个新的 Image() 实例。它越快到达 loaded 钩子,您的 JavaScript 线程就会越快被释放。

使用 getItemLayout

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

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

使用 keyExtractor 或 key

您可以为 FlatList 组件设置 keyExtractor。此 prop 用于缓存,并作为 React key 来跟踪项目重新排序。

您也可以在项目组件中使用 key prop。

避免在 renderItem 上使用匿名函数

对于函数组件,将 renderItem 函数移到返回的 JSX 之外。此外,请确保将其包裹在 useCallback 钩子中,以防止每次渲染都重新创建它。

对于类组件,将 renderItem 函数移到 render 函数之外,这样它就不会在每次调用 render 函数时都重新创建自身。

tsx
const renderItem = useCallback(({item}) => (
<View key={item.key}>
<Text>{item.title}</Text>
</View>
), []);

return (
// ...

<FlatList data={items} renderItem={renderItem} />;
// ...
);