如何使用ReactNative 0.43改善大型列表的FlatList渲染性能?

时间:2017-04-13 03:32:05

标签: performance react-native react-native-flatlist

我正在尝试使用RN0.43中的FlatList在3列中渲染〜250个图像的列表,并且我在FlatList的onLayout函数中更改图像的宽度以适合屏幕的宽度。

初始性能还可以,但是在向上/向下滚动一些后,有时需要一秒钟或2秒才能显示图像。

如果我改为屏幕方向则更糟糕,更新屏幕需要2~3秒。

一些调查结果:

    屏幕旋转后
  1. ,在调用FlatList.onLayout之前需要一秒或2秒

  2. 在FlatList.onLayout和图像宽度更新之后,每个图像(大约一半的列表,~150个图像;虽然只显示~15个)渲染2~4次,而render()只被调用一次。

  3. 问题:

    1. 如何修改代码以提高性能?
    2. 在多列列表的getItemLayout()中,偏移量应该是(itemHeight + separatorHeight)*(index%numColumns)吗?
    3. 感谢。

      测试:GalaxySII(4.1.2)和Android SDK模拟器(7.1.1)

      var data = [
          require('./res/img/Search.png'),
          require('./res/img/test - Copy.png'),
          // ~250 items
          ...];
      
      class app extends React.Component {
          renderItem (info, width) {
              console.log('renderItem', info.index);
              if(width !== this.width) {
                  this.imageStyle = {width: width-MarginHorizontal , height: width-MarginHorizontal, resizeMode: 'contain'};
              }
              return (
                  <Image
                      source = {info.item}
                      key = {info.index}
                      style={this.imageStyle}/>
                  );
          }
      
          render() {
              console.log('Test.render');
              return (
                  <View style={{
                      flex: 1,
                      flexDirection: 'row',
                      justifyContent: 'flex-start',
                      alignItems: 'center',
                      backgroundColor: '#F5FCFF'
                  }}>
                      <GridList
                          numColumns={3}
                          columnWrapperStyle={{ alignItems: 'center', marginVertical: 5, justifyContent: 'space-around'}}
                          data={data}
                          renderItem={this.renderItem}
                      />
                  </View>
              );
          }
      }
      
      class GridList extends Component {
          onLayout(event) {
              console.log('GridList.onLayout()');
              let newColumnWidth = event.nativeEvent.layout.width/ this.numColumns;
              this.layout = Object.assign({},event.nativeEvent.layout);
              if( undefined === this.columnWidth  || Math.abs(newColumnWidth - this.columnWidth) > WidthTolerance ) {
                  this.columnWidth = newColumnWidth;
                  if(this.isComponentMounted) {
                      this.setState({renderCount: this.state.renderCount+1});
                  } else {
                      this.state.renderCount +=1;
                  }
              }
          }
          render() {
              console.log('GridList.render()');
              return (
                  <FlatList
                      {...(this.modifiedProps)}
                      renderItem={(info) => { return this.props.renderItem(info, this.columnWidth); }}>
                      {this.props.children}
                  </FlatList>
              );
          }
      }
      

5 个答案:

答案 0 :(得分:5)

免责声明:我知道这个问题已经过时了,但无论如何这是我的回答。

我的应用程序有一个包含500多个项目的列表。所以,我们达到了应用程序崩溃在流行的非坏手机上的程度。然后我做了this extensive research about performance on FlatLists.

FlatList组件是旧ScrollView的替代品。问题是ScrollViews一次呈现所有列表,因此它们在视觉上表现更好,但内存消耗存在折衷,导致应用程序崩溃。

所以扁平列表是必要的邪恶。它们基本上只渲染可见的项目,这是内存消耗的巨大收益,但视觉性能的痛苦,特别是对于繁重/复杂的项目,恰好是这些响应式图像的情况。

如何解决?

您可以实施许多策略来缓解您的问题。

  • 使用缓存和效果图像,例如react-native-fast-image。您可以删除或缩写以释放Javascript线程的每个操作:执行此操作(每个图像都是new Image(),因此,如果它们被缓存,则会更快地调用loaded挂钩)

  • 您的列表项组件是一个只读组件,应该是“哑”。根据需要实施shouldComponentUpdate() { return false }或更加可靠的更新控制方法。这是巨大的性能提升。

  • 删除列表附近任何位置的console.logs。他们使Javascript线程变得非常糟糕。

  • 构建您的应用以进行制作并对其进行测试。它几乎总是快两倍或三倍。由于调试,Dev env很慢。

  • 给予this article更好的阅读以获得更多策略。

结论

FlatList IS 是一个缓慢的组件。这是known, open and well documented issue。尽你所能改进它,让我们希望未来的版本可以解决这个问题。

答案 1 :(得分:0)

是的我遇到了同样的问题 - 多张图片&amp;反应原生的列表中的视频所以我删除了Flatlist而不是这个我更喜欢使用ListView快速渲染&amp;修复列表项上的可触摸性问题,但不要忘记将PureComponent设置为列表项

答案 2 :(得分:0)

您将为列表的每一行单独重新创建许多样式对象。这为JS-&gt; Native桥提供了大量流量。尝试使用样式表而不是内联样式。

答案 3 :(得分:0)

我强烈建议大家阅读下面所附链接中的文章,以优化您的单位列表。 https://reactnative.dev/docs/0.60/optimizing-flatlist-configuration

答案 4 :(得分:-1)

尝试使用keyExtractor

为每个项目设置唯一键

例如:

render() {
  return (
    <List>
      <FlatList
        ...
        keyExtractor={item => item.email}
      />
    </List>
  );
}