【问题标题】:React-Native FlatList performance problems with large list大型列表的 React-Native FlatList 性能问题
【发布时间】:2018-05-20 14:38:19
【问题描述】:

我的代码使用FlatList 将 Json 数据获取到一个数组中列出了数据。它看起来像是连续的电话簿照片和文字。

这是我的代码:

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

【问题讨论】:

    标签: javascript react-native react-native-android react-native-flatlist


    【解决方案1】:

    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 无法以足够快的速度呈现您的项目,因此您在列表的一部分上输入了未呈现的组件。

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


    道具

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

    removeClippedSubviews

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

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

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

    maxToRenderPerBatch

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

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

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

    initialNumToRender

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

    赢:您可以将此值设置为每个设备的屏幕上的精确项目数。这可以在渲染列表组件时大大提升性能。

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

    窗口大小

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

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

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

    遗留实现

    This prop,如果为真,则让您的 FlatList 依赖于旧的 ListView,而不是 VirtualizedList。

    胜利:这肯定会让您的列表表现得更好,因为它消除了虚拟化并一次渲染所有项目。

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

    禁用虚拟化

    你会看到人们在一些问题上提倡使用这个道具。但是this is deprecated now。这曾经做类似legacyImplementation的事情。


    列出项目

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

    使用简单的组件

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

    使用灯光组件

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

    使用 shouldComponentUpdate

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

    shouldComponentUpdate() {
      return false
    }
    

    【讨论】:

    • 在大多数情况下,这看起来像是优化 FlatList 配置的 react-native 文档的副本。我认为您应该链接原始文档facebook.github.io/react-native/docs/…
    • @Tyler 如果你深入挖掘,你会看到文档的这一部分is a PR based on my article。所以这里的这篇文章就是这一切的起源。
    • 这是有用的信息,但我有一个问题:多少才算太多?我对参数进行了试验,发现在我的情况下(每个列表项都有一个带有 2 个图像和一些文本的滑块)windowSize=30 和 maxToRenderPerBatch=60 可以平滑滚动。但我担心这些数字是否太大
    • @GennadyDogaev 这确实是个案。对我来说,它看起来不错。 windowssize 的默认值甚至是 21。每批的最大渲染量有点高(你基本上是在每次滚动渲染所有项目),但如果它有效,那就没问题了。我认为你对这个配置很酷!
    【解决方案2】:

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

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

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多