Подтвердить что ты не робот

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

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

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

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

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

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

  • после FlatList.onLayout и обновления ширины изображения, каждое изображение (примерно половина списка, ~ 150 изображений, пока отображается только ~ 15) отображается 2 ~ 4 раза, а render() вызывается только один раз.

Вопрос:

  • Как я могу изменить код для повышения производительности?
  • в 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>
        );
    }
}
4b9b3361

Ответ 1

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

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

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

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

Как обойти?

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

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

  • Ваш компонент элемента списка является компонентом только для чтения, который должен быть "тупым". shouldComponentUpdate() { return false } или более надежный метод управления обновлениями по мере необходимости. Это ОГРОМНОЕ повышение производительности.

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

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

  • Дайте эту статью хорошее чтение для большего количества стратегий.

Заключение

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

Ответ 2

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

Ответ 3

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

Ответ 4

Техника, использованная в этой статье, может оказаться полезной, по крайней мере, для меня. Я попробовал несколько других методов и не смог сделать быстрее.

Делаем FlatList в 5 раз быстрее

Ответ 5

Попробуйте установить уникальный ключ для каждого элемента, используя keyExtractor

Пример:

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