Проблема итерации по вызовам onLayout для предоставления высоты строк элементов в getLtemLayout FlatList - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть FlatList, который заполняет около 18000 строк текста.Поскольку текст в каждой строке имеет переменную длину, я не могу предоставить статическую высоту для использования в getItemLayout.

То, что я пытаюсь сделать, это сначала выполнить итерацию по всему набору данных с использованием фиктивного представления, из которого я собираюизмерение высоты через onLayout.Моя проблема в том, что в настоящее время представление перерисовывается только около 10 раз, прежде чем оно просто останавливается.Насколько я могу судить, onLayout просто не вызывается для последнего представления, которое в итоге появляется на экране - которое опять-таки только 10-е (или около того, в зависимости от интервала, в котором я перебираю данные).

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

import React, { Component } from 'react';
import { AppRegistry, Text, View, TouchableOpacity, StyleSheet } from 'react-native';


export default class DummyMainItem extends Component {
constructor(props) {
    super(props);
    this.state = {
        codeData: [],
        currentItem: -1,
    };
}

componentWillReceiveProps(nextProps) {
    // Get data from MainFlatList
    if (nextProps.codeData != '') {
        console.log("PROPS in DummyMainItem are codeData of length: " + nextProps.codeData.length);
        this.setState({ codeData: nextProps.codeData });
    }
}


getItemDimensions(layout) {
    const { x, y, width, height } = layout;
    curItem = this.state.currentItem;
    console.log("getItemDimensions of #" + curItem + " (width, height) : (" + width + ", " + height + ")");

    if (curItem <= this.state.codeData.length) {
        this.setState({ currentItem: curItem + 1 });
    }
}

render() {
    console.log("Dummy Rendering item #" + this.state.currentItem);

    if (this.state.codeData != null && this.state.codeData.length > 0) {

        var item = this.state.codeData[this.state.currentItem];

        switch (item.type) {
            case '0':
                console.log("Dummy Case 0 FULLTEXT: " + item.fulltext);
                return (
                    <TouchableOpacity>
                        <View onLayout={(event) => { this.getItemDimensions(event.nativeEvent.layout) }}>
                            <View>
                                <Text>{item.fulltext}</Text>
                            </View>
                        </View>
                    </TouchableOpacity>
                );

            case '1':
                console.log("Dummy Case 1 FULLTEXT: " + item.fulltext);
                return (
                    <TouchableOpacity>
                        <View onLayout={(event) => { this.getItemDimensions(event.nativeEvent.layout) }}>
                            <View>
                                <Text>{item.fulltext}</Text>
                            </View>
                        </View>
                    </TouchableOpacity>
                );
            case '2':
                console.log("Dummy Case 2 FULLTEXT: " + item.fulltext);
                return (
                    <TouchableOpacity>
                        <View onLayout={(event) => { this.getItemDimensions(event.nativeEvent.layout) }}>
                            <View style={{ flexDirection: 'row' }}>
                                <Text>{item.section}</Text>
                                <Text>{item.fulltext}</Text>
                            </View>
                        </View>
                    </TouchableOpacity>
                );

            default:
                return (
                    <TouchableOpacity>
                        <View>
                            <View onLayout={(event) => { this.getItemDimensions(event.nativeEvent.layout) }}>
                                <Text>{item.type} {item.fulltext} </Text>
                            </View>
                        </View>
                    </TouchableOpacity>
                );
        }

    } else {
        console.log("Dummy Case Blank Render");
        return (
            <TouchableOpacity>
                <View onLayout={(event) => { this.getItemDimensions(event.nativeEvent.layout) }}>
                    <View>
                        <Text> </Text>
                    </View>
                </View>
            </TouchableOpacity>
        )
    }

}
}

AppRegistry.registerComponent('DummyMainItem', () => DummyMainItem);

Я ожидал бы от своего кода, что каждый раз при визуализации представления,Будет вызвана функция getItemDimensions (), которая сама регулирует состояние this.state.currentItem, это изменение состояния вызывает повторную активацию функции render ().

Фактическое поведение заключается в том, что она выполняет вышеупомянутые, но только ограниченное количество раз (ближе к 10, чем мне нужно 18000).Функция getItemDimensions () не вызывается методом onLayout, поэтому измерения не получаются, а состояние currentItem не улучшается - поэтому рендеринг останавливается.Что я не понимаю, так это то, почему для любого последнего представления, отображаемого на экране, onLayout не вызывает getItemDimensions.

Кто-нибудь знает, почему остановка итерации или более эффективный способ достижения моей цели?Мне нужно предоставить getItemLayout для моего FlatList, поскольку приложение должно иметь возможность ScrollToIndex, прежде чем пользователь вручную прокрутит весь FlatList.

1 Ответ

0 голосов
/ 07 февраля 2019

Проблема с не вызываемым onLayout возникла из-за того, что onLayout не произойдет, если не будет разницы между предыдущим макетом и тем, который его заменяет.В моем случае, когда 2 представления с одинаковой высотой следовали друг за другом, итерация остановилась бы из-за того, что onLayout больше не вызывался.

Простое решение - дать каждому представлению уникальный идентификатор для ответа на этот вопрос: Принудительное включение onLayout в собственном представлении React .то есть:

<View onLayout={(event) => { this.getItemDimensions(event.nativeEvent.layout) }} 
    key={this.state.currentItem}>

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

К сожалению, это кажется единственнымспособ генерирования необходимой информации о высоте и смещении, которая требуется getItemLayout (), чтобы разрешить операции ScrollTo для FlatLists с переменной высотой.Это решение, хотя и функциональное, в конечном счете слишком медленное, чтобы быть полезным для меня с 18000 элементов списка, и, учитывая, что мое исследование не нашло никаких альтернатив этому пункту для React-Native, сейчас я настоятельно рекомендую вернуть свое приложение на чистый нативныйразвитие.

...