Как улучшить производительность визуализации FlatList для большого списка с помощью ReactNative 0.43?

Я пытаюсь отобразить список из ~ 250 изображений в 3 столбца, используя FlatList в RN0.43, и я изменяю ширину изображений в функции onLayout FlatList, чтобы соответствовать ширине экрана.

Первоначальная производительность в порядке, но после некоторой прокрутки вверх / вниз иногда требуется секунда или 2, пока не появятся изображения.

еще хуже, если я перейду на ориентацию экрана, обновление экрана займет 2–3 секунды.

несколько выводов:

  1. после поворота экрана требуется секунда или 2, пока не будет вызван FlatList.onLayout

  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>
        );
    }
}

person John Ng    schedule 13.04.2017    source источник
comment
Я вижу это в 0.45.1, есть ли прогресс?   -  person sooper    schedule 03.07.2017


Ответы (5)


Отказ от ответственности: я знаю, что вопрос старый, но все равно вот мой ответ.

В моем приложении есть списки с более чем 500 элементами. Итак, мы дошли до того, что приложение вылетало на популярных неплохих телефонах. Затем я провел это обширное исследование эффективности в FlatLists.

Компонент FlatList был представлен как альтернатива старому ScrollView. Проблема в том, что ScrollViews визуализируют весь ваш список одновременно, поэтому они визуально работают лучше, но есть компромисс в потреблении памяти, что приводит к сбоям приложения.

Так что плоские списки - неизбежное зло. По сути, они визуализируют только видимые элементы, что значительно увеличивает потребление памяти, но затрудняет визуальную производительность, особенно для тяжелых / сложных элементов, что бывает в вашем случае с этими отзывчивыми изображениями.

Как обойтись?

Есть много стратегий, которые вы можете реализовать, чтобы смягчить вашу проблему.

  • Используйте кэшированные и эффективные изображения, такие как react-native-fast-image. Каждая операция, которую вы можете удалить или сократить для освобождения потока Javascript: сделайте это (каждое изображение - это new Image(), поэтому, если они кэшированы, ваш хук loaded вызывается раньше)

  • Компонент вашего элемента списка - это компонент только для чтения, который должен быть «тупым». При необходимости используйте shouldComponentUpdate() { return false } или более надежный метод управления обновлениями. Это ОГРОМНЫЙ прирост производительности.

  • Удалите console.logs где-нибудь рядом со своим списком. Они очень сильно замедляют поток Javascript.

  • Создайте свое приложение для производства и протестируйте его. Он становится почти всегда в два-три раза быстрее. Dev env работает медленно из-за отладки.

  • Прочтите эту статью, чтобы узнать о других стратегиях.

Заключение

FlatList ЯВЛЯЕТСЯ медленным компонентом. Это известная, открытая и хорошо задокументированная проблема. Сделайте все возможное, чтобы улучшить его, и будем надеяться, что в будущих выпусках это исправят.

person Filipe Merker    schedule 06.06.2018

Да, у меня была такая же проблема - несколько изображений и видео в списке в нативной реакции. Поэтому я удалил Flatlist вместо этого. Я предпочел использовать ListView для быстрого рендеринга и исправления проблемы с осязанием в элементе списка, но не забудьте установить PureComponent для элемента списка

person priyanka    schedule 18.05.2018

Вы повторно создаете множество объектов стиля для каждой строки списка индивидуально. Это увеличивает нагрузку на мост JS-> Native. Попробуйте использовать таблицу стилей вместо того, чтобы передавать стили встроенными.

person vonovak    schedule 02.06.2018

Я настоятельно рекомендую всем прочитать статью по ссылке ниже, чтобы оптимизировать свой плоский список. https://reactnative.dev/docs/optimizing-flatlist-configuration

person Pratik Adhikari    schedule 28.02.2020