跳到主要内容

优化 Flatlist 配置

术语

  • VirtualizedList: FlatList 背后的组件 (React Native 对 Virtual List 概念的实现。)

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

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

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

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

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

属性

以下是可以帮助提高 FlatList 性能的属性列表

removeClippedSubviews

类型默认值
布尔值False

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

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

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

maxToRenderPerBatch

类型默认值
数字10

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

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

缺点: 每个批次的项目越多,意味着 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 中的组件。

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(),以便仅当指定的属性更改时才重新渲染组件。 如果比较函数返回 true,则不会重新渲染组件。

使用缓存的优化图像

你可以使用社区包(例如来自 @DylanVannreact-native-fast-image)来获得更高性能的图像。 列表中的每个图像都是一个新的 Image() 实例。 它到达 loaded 钩子的速度越快,你的 JavaScript 线程就会越快地再次空闲。

使用 getItemLayout

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

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

使用 keyExtractor 或 key

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

你也可以在你的项目组件中使用 key 属性。

避免在 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} />;
// ...
);