大列表的 React-Native FlatList 性能问题

新手上路,请多包涵

我的代码将 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 秒,这对用户来说很烦人。我应该怎么做才能让它更快?

原文由 bucsy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

2019 年 12 月 20 日编辑:有关此答案的信息成为 官方文档 的一部分。你应该检查一下!


18 年 5 月 26 日编辑:这个答案 在 github 上变得更大更完整


如果你关注 这个线程,你会发现 React 的团队已经意识到这个性能问题。

这个问题没有灵丹妙药,你必须考虑每种方法的权衡,以及你认为对你的观众来说什么是好的体验。但幸运的是,您可以尝试进行一些调整并改进您的 FlatList


术语和含义

有很多术语(在 文档 或一些问题上)一开始让我感到困惑。所以,让我们从一开始就解决这个问题。

  • VirtualizedListFlatList 背后的组件,是 React Native 对“ 虚拟列表”概念的实现。

  • Performance ,在这种情况下,意味着平滑(而不是断断续续)滚动(以及导航进出列表)体验。

  • 在此上下文中, 内存消耗 是指有多少有关您的列表的信息存储在内存中,这可能会导致应用程序崩溃。

  • 空白区域 意味着 VirtualizedList 无法足够快地呈现您的项目,因此您在列表的一部分上输入了未呈现的组件。

  • 此处的 窗口 不是您的视口,而是应该呈现项目的区域的大小。


道具

改进 FlatList 的一种方法是调整它的道具。以下是可以帮助您的道具列表。

removeClippedSubviews

您可以将 removeClippedSubviews 属性设置为 true,这会卸载窗口外的组件。

Win: 这对内存非常友好,因为您总会有一个小的渲染列表。

权衡: 请注意,此实现可能存在错误,例如如果您在不会卸载的组件(例如导航路线)上使用它会丢失内容。它的性能也可能较低,在不太好的设备上为包含复杂项目的大列表提供断断续续的滚动动画,因为它会在每次滚动时进行疯狂的计算。

maxToRenderPerBatch

您可以设置 maxToRenderPerBatch={number} ,这是一个 VirtualizedList 道具,可以直接传递给 FlatList 。有了这个,您可以控制每批渲染的项目数量,这是在每个滚动上渲染的下一个项目块。

胜利: 设置更大的数字意味着滚动时视觉空白区域更少(填充率更好)。

权衡: 每批次的项目越多意味着 JavaScript 性能越低,这意味着响应速度越低(单击一个项目并打开详细信息)。如果您有一个静态和非交互式列表,这可能是可行的方法。

initialNumToRender

您可以设置 initialNumToRender={number} 。这意味着要呈现的项目的初始数量。

获胜: 您可以将此值设置为覆盖每台设备屏幕的项目的精确数量。这在渲染列表组件时可以大大提高性能。

权衡: 设置低 initialNumToRender 时,您最有可能看到空白区域。

窗口大小

您可以设置 windowSize={number} 。这里传递的数字是一个测量单位,其中 1 等于您的视口高度。默认值为 21,上方 10 个视口,下方 10 个,中间 1 个。

Win: 如果你主要担心性能,你可以设置一个更大的 windowSize 这样你的列表将运行流畅并且空白更少。如果你主要担心内存消耗,你可以设置一个较低的 windowSize 所以你的渲染列表会更小。

权衡: 对于更大的 windowSize ,你将有更大的内存消耗。对于较低的 windowSize ,您将获得较低的性能和看到空白区域的较大变化。

遗留实施

这个道具,如果为真,让你的 FlatList 依赖旧的 ListView ,而不是 VirtualizedList

赢: 这肯定会让你的列表表现得更好,因为它消除了虚拟化并一次呈现你的所有项目。

权衡取舍: 您的内存消耗达到顶峰,并且包含复杂项目的大列表(100 多个)很可能会使您的应用程序崩溃。它还会发出警告,指出上述调整将不起作用,因为您现在位于 ListView 上。

禁用虚拟化

你会看到人们提倡在某些问题上使用这个道具。但这 现在已被弃用。这用于执行类似于 legacyImplementation 的操作。


清单项目

还有一些双赢策略涉及您的列表项组件。它们经常由 VirtualizedList 管理,因此它们需要快速。

使用简单的组件

您的组件越复杂,它们呈现的速度就越慢。尽量避免在列表项中出现大量逻辑和嵌套。如果您在您的应用程序中大量重复使用此列表项组件,请仅为您的大列表创建一个副本,并尽可能减少它们的逻辑和嵌套。

使用轻组件

您的组件越重,渲染速度就越慢。避免沉重的图像(对列表项使用裁剪版本,尽可能小)。与您的设计团队交谈,在列表中使用尽可能少的效果、交互和信息。将它们保存到您的项目的详细信息中。

使用 shouldComponentUpdate

对您的组件实施更新验证。 React 的 PureComponent 主要用于你没有时间思考的时候。如果您正在阅读本文,您确实有时间,因此,为您的列表项组件创建最严格的规则。如果您的列表足够简单,您甚至可以使用

shouldComponentUpdate() {
  return false
}

原文由 Filipe Merker 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以通过以下改进来优化平面列表:

  1. 分页
    • 您可以在后端对数据进行分页,并在滚动接近末尾时重新获取它。 onEndReachedonEndReachedThreshold 可以帮助你。
  2. 将您的 React Native 版本更新到 49 或最新版本
    • Fiber 16 具有惊人的性能提升,让一切运行得更快、更流畅
  3. 使用 PureComponent 渲染项目
    • PureComponent 改进了组件的渲染和内存使用,将渲染项创建为 pure 为您提供更好的性能体验
  4. 定义 getItemLayout 道具
    • 它改进了项目渲染,因为 React 之前会知道它的布局定义

希望能帮助到你

原文由 soutot 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题