大列表的 React-Native FlatList 性能问题
React-Native FlatList performance problems with large list
我的代码获取 Json 数据到一个数组,使用 FlatList
列出数据。看起来像是电话簿照片和文字排成一行。
这是我的代码:
renderItem = ({ item }) =>
(
<ListItem
title={item.username}
avatar={{ uri: item.photo }}
/>
)
render() {
console.log(this.state.myData);
return (
<View style={styles.container}>
<FlatList
data={this.state.myData}
renderItem={this.renderItem}
/>
</View>
);
}
它工作正常,我得到了输出,但性能很慢。渲染大约需要 10 秒,这对用户来说很烦人。我应该怎么做才能让它更快?
您可以通过以下改进来优化平面列表:
- 分页
- 您可以在后端对数据进行分页,并在滚动接近末尾时重新提取数据。
onEndReached
和 onEndReachedThreshold
可以帮助你。
- 将您的 React Native 版本更新到 49 或最新版本
- Fiber 16 有惊人的性能提升,让一切运行得更快更流畅
- 对渲染项使用
PureComponent
PureComponent
改进了组件的渲染和内存使用,将渲染项创建为 pure 可为您提供更好的性能体验
- 定义
getItemLayout
道具
- 它改进了项目渲染,因为 React 事先知道它的布局定义
希望对您有所帮助
2019 年 12 月 20 日编辑:有关此答案的信息已成为 official docs 的一部分。你应该检查一下!
编辑 2018 年 5 月 26 日:这个答案变成了 bigger and more complete post on github
如果你关注 this thread,你会发现 React 的团队已经意识到这个性能问题。
这个问题没有灵丹妙药,您必须权衡每种方法的利弊,以及您认为对您的观众来说是好的体验。但幸运的是,您可以尝试进行一些调整来改进您的 FlatList
.
术语和含义
有很多术语(在 docs 或某些问题上)一开始让我感到困惑。所以,让我们从一开始就解决这个问题。
VirtualizedList是FlatList
背后的组件,是React Native对'virtual list'概念的实现。
性能,在这种情况下,意味着平滑(不不稳定)滚动(以及导航进出列表)体验。
内存消耗,在此上下文中,是关于您的列表的多少信息存储在内存中,这可能会导致应用程序崩溃。
空白区域 意味着 VirtualizedList 无法足够快地渲染您的项目,因此您在列表的一部分上输入了未渲染的组件。
Window 这里不是您的视口,而是应渲染项目的区域大小。
道具
改进 FlatList
的一种方法是调整它的道具。以下是可以帮助您的道具列表。
删除剪辑的子视图
您可以将 removeClippedSubviews
属性设置为 true,这会卸载 window 之外的组件。
Win: 这对内存非常友好,因为您总会有一个小的渲染列表。
权衡:请注意,此实现可能存在错误,例如如果您在不会卸载的组件(例如导航路线)上使用它会丢失内容.
它的性能也可能较低,在不太好的设备上为包含复杂项目的大列表提供断断续续的滚动动画,因为它会在每次滚动时进行疯狂的计算。
maxToRenderPerBatch
您可以设置 maxToRenderPerBatch={number}
,这是一个 VirtualizedList
道具,可以直接传递给 FlatList
。有了这个,您可以控制每批渲染的项目数量,这是每次滚动时渲染的下一个项目块。
Win:设置一个更大的数字意味着滚动时视觉空白区域更少(更好的填充率)。
权衡: 每批次的项目越多意味着性能越差 JavaScript,这意味着响应速度越慢(单击项目并打开详细信息)。如果您有一个静态和非交互式列表,这可能是您要走的路。
initialNumToRender
可以设置initialNumToRender={number}
。这意味着要呈现的项目的初始数量。
Win: 您可以将此值设置为覆盖每个设备屏幕的精确项目数。这在渲染列表组件时可以大大提高性能。
权衡: 设置较低的 initialNumToRender
.
时,您最有可能看到空白区域
window尺寸
可以设置windowSize={number}
。这里传递的数字是一个测量单位,其中 1 等于您的视口高度。默认值为 21,上方 10 个视口,下方 10 个,中间 1 个。
Win: 如果您主要担心性能,您可以设置更大的 windowSize
这样您的列表就会 运行 平滑并且空白更少space。如果你主要担心内存消耗,你可以设置一个较低的 windowSize
这样你的渲染列表就会更小。
权衡: 对于更大的 windowSize
,您将有更大的内存消耗。对于较低的 windowSize
,您的性能会降低,看到空白区域的变化会更大。
遗留实施
This prop,当为真时,使您的 FlatList
依赖于较旧的 ListView
,而不是 VirtualizedList
。
Win: 这肯定会使您的列表表现更好,因为它消除了虚拟化并同时呈现所有项目。
权衡: 您的内存消耗达到顶峰,并且包含复杂项目的大列表(100 多个)很可能会使您的应用程序崩溃。
它还会发出警告,指出上述调整将不起作用,因为您现在位于 ListView 上。
禁用虚拟化
你会看到人们在一些问题上提倡使用这个道具。但是this is deprecated now。这曾经做类似于 legacyImplementation
.
的事情
列表项
还有一些双赢策略涉及您的列表项组件。它们经常由 VirtualizedList 管理,因此它们需要快速。
使用简单的组件
组件越复杂,渲染速度就越慢。尽量避免在列表项中出现大量逻辑和嵌套。如果您在应用程序中大量重复使用此列表项组件,请仅为您的大列表创建一个副本,并尽可能减少它们的逻辑和嵌套。
使用灯光组件
您的组件越重,渲染速度就越慢。避免沉重的图像(对列表项使用裁剪版本,尽可能小)。与您的设计团队交谈,在列表中使用尽可能少的效果、交互和信息。将它们保存到您的项目的详细信息中。
使用 shouldComponentUpdate
对您的组件实施更新验证。 React 的 PureComponent 主要用于你没有时间思考的时候。如果您正在阅读本文,您确实有时间,因此,为您的列表项组件创建最严格的规则。如果您的列表足够简单,您甚至可以使用
shouldComponentUpdate() {
return false
}
将您的 <FlatList>
包裹在 <ScrollView>
中以防止在大型数据集上出现白页和性能问题
我的代码获取 Json 数据到一个数组,使用 FlatList
列出数据。看起来像是电话簿照片和文字排成一行。
这是我的代码:
renderItem = ({ item }) =>
(
<ListItem
title={item.username}
avatar={{ uri: item.photo }}
/>
)
render() {
console.log(this.state.myData);
return (
<View style={styles.container}>
<FlatList
data={this.state.myData}
renderItem={this.renderItem}
/>
</View>
);
}
它工作正常,我得到了输出,但性能很慢。渲染大约需要 10 秒,这对用户来说很烦人。我应该怎么做才能让它更快?
您可以通过以下改进来优化平面列表:
- 分页
- 您可以在后端对数据进行分页,并在滚动接近末尾时重新提取数据。
onEndReached
和onEndReachedThreshold
可以帮助你。
- 您可以在后端对数据进行分页,并在滚动接近末尾时重新提取数据。
- 将您的 React Native 版本更新到 49 或最新版本
- Fiber 16 有惊人的性能提升,让一切运行得更快更流畅
- 对渲染项使用
PureComponent
PureComponent
改进了组件的渲染和内存使用,将渲染项创建为 pure 可为您提供更好的性能体验
- 定义
getItemLayout
道具- 它改进了项目渲染,因为 React 事先知道它的布局定义
希望对您有所帮助
2019 年 12 月 20 日编辑:有关此答案的信息已成为 official docs 的一部分。你应该检查一下!
编辑 2018 年 5 月 26 日:这个答案变成了 bigger and more complete post on github
如果你关注 this thread,你会发现 React 的团队已经意识到这个性能问题。
这个问题没有灵丹妙药,您必须权衡每种方法的利弊,以及您认为对您的观众来说是好的体验。但幸运的是,您可以尝试进行一些调整来改进您的 FlatList
.
术语和含义
有很多术语(在 docs 或某些问题上)一开始让我感到困惑。所以,让我们从一开始就解决这个问题。
VirtualizedList是
FlatList
背后的组件,是React Native对'virtual list'概念的实现。性能,在这种情况下,意味着平滑(不不稳定)滚动(以及导航进出列表)体验。
内存消耗,在此上下文中,是关于您的列表的多少信息存储在内存中,这可能会导致应用程序崩溃。
空白区域 意味着 VirtualizedList 无法足够快地渲染您的项目,因此您在列表的一部分上输入了未渲染的组件。
Window 这里不是您的视口,而是应渲染项目的区域大小。
道具
改进 FlatList
的一种方法是调整它的道具。以下是可以帮助您的道具列表。
删除剪辑的子视图
您可以将 removeClippedSubviews
属性设置为 true,这会卸载 window 之外的组件。
Win: 这对内存非常友好,因为您总会有一个小的渲染列表。
权衡:请注意,此实现可能存在错误,例如如果您在不会卸载的组件(例如导航路线)上使用它会丢失内容. 它的性能也可能较低,在不太好的设备上为包含复杂项目的大列表提供断断续续的滚动动画,因为它会在每次滚动时进行疯狂的计算。
maxToRenderPerBatch
您可以设置 maxToRenderPerBatch={number}
,这是一个 VirtualizedList
道具,可以直接传递给 FlatList
。有了这个,您可以控制每批渲染的项目数量,这是每次滚动时渲染的下一个项目块。
Win:设置一个更大的数字意味着滚动时视觉空白区域更少(更好的填充率)。
权衡: 每批次的项目越多意味着性能越差 JavaScript,这意味着响应速度越慢(单击项目并打开详细信息)。如果您有一个静态和非交互式列表,这可能是您要走的路。
initialNumToRender
可以设置initialNumToRender={number}
。这意味着要呈现的项目的初始数量。
Win: 您可以将此值设置为覆盖每个设备屏幕的精确项目数。这在渲染列表组件时可以大大提高性能。
权衡: 设置较低的 initialNumToRender
.
window尺寸
可以设置windowSize={number}
。这里传递的数字是一个测量单位,其中 1 等于您的视口高度。默认值为 21,上方 10 个视口,下方 10 个,中间 1 个。
Win: 如果您主要担心性能,您可以设置更大的 windowSize
这样您的列表就会 运行 平滑并且空白更少space。如果你主要担心内存消耗,你可以设置一个较低的 windowSize
这样你的渲染列表就会更小。
权衡: 对于更大的 windowSize
,您将有更大的内存消耗。对于较低的 windowSize
,您的性能会降低,看到空白区域的变化会更大。
遗留实施
This prop,当为真时,使您的 FlatList
依赖于较旧的 ListView
,而不是 VirtualizedList
。
Win: 这肯定会使您的列表表现更好,因为它消除了虚拟化并同时呈现所有项目。
权衡: 您的内存消耗达到顶峰,并且包含复杂项目的大列表(100 多个)很可能会使您的应用程序崩溃。 它还会发出警告,指出上述调整将不起作用,因为您现在位于 ListView 上。
禁用虚拟化
你会看到人们在一些问题上提倡使用这个道具。但是this is deprecated now。这曾经做类似于 legacyImplementation
.
列表项
还有一些双赢策略涉及您的列表项组件。它们经常由 VirtualizedList 管理,因此它们需要快速。
使用简单的组件
组件越复杂,渲染速度就越慢。尽量避免在列表项中出现大量逻辑和嵌套。如果您在应用程序中大量重复使用此列表项组件,请仅为您的大列表创建一个副本,并尽可能减少它们的逻辑和嵌套。
使用灯光组件
您的组件越重,渲染速度就越慢。避免沉重的图像(对列表项使用裁剪版本,尽可能小)。与您的设计团队交谈,在列表中使用尽可能少的效果、交互和信息。将它们保存到您的项目的详细信息中。
使用 shouldComponentUpdate
对您的组件实施更新验证。 React 的 PureComponent 主要用于你没有时间思考的时候。如果您正在阅读本文,您确实有时间,因此,为您的列表项组件创建最严格的规则。如果您的列表足够简单,您甚至可以使用
shouldComponentUpdate() {
return false
}
将您的 <FlatList>
包裹在 <ScrollView>
中以防止在大型数据集上出现白页和性能问题