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

Joh*_* Ng 18 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()只调用一次.

题:

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

谢谢.

测试: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>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

Fil*_*ker 7

免责声明:我知道问题是陈旧的,但无论如何,这是我的回答.

我的应用程序有一个包含500多个项目的列表.所以,我们达到了应用程序崩溃在流行的非坏手机上的程度.然后我对FlatLists的性能进行了广泛的研究.

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

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

如何解决?

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

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

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

  • 删除列表附近任何位置的console.logs.他们减慢Javascript线程的速度非常糟糕.

  • 构建您的应用程序以进行生产并进行测试 它几乎总是快两倍或三倍.由于调试,Dev env很慢.

  • 给这篇文章很好看的更多的策略.

结论

FlatList 是一个缓慢的组成部分 这是一个众所周知,开放且记录良好的问题.尽你所能来改进它,让我们希望未来的版本可以解决这个问题.


小智 -1

尝试使用keyExtractor为每个项目设置唯一的键

例如:

render() {
  return (
    <List>
      <FlatList
        ...
        keyExtractor={item => item.email}
      />
    </List>
  );
}
Run Code Online (Sandbox Code Playgroud)