Linked Questions

Popular Questions

I have a FlatList which fills with about 18000 text rows. Because the text in each row is of variable length, I cannot provide a static height for use in getItemLayout.

What I am attempting to do is first iterate through the entire dataset using a dummy view, from which I collect the height dimension via onLayout. My issue is that currently, the view is only re-rendering around 10 times before it just stops. As far as I can tell, onLayout simply isn't called for the last view that ends up appearing on the screen -- which is again only the 10th (or so, depending on the interval I iterate through the data at).

Below is my code which I've attempted to simplify somewhat here. Currently just trying to find a way to iterate through and precalculate view heights for the entire data set ahead of rendering in a separate component.

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

I would expect from my code that each time a view was rendered, the getItemDimensions() function would be called, which itself adjusts the state of this.state.currentItem, this state change causing the render() function to be triggered again.

The actual behaviour is that it does the above, but only a limited number of times (closer to about 10 than the 18000 I need). getItemDimensions() is not called by onLayout, so dimensions are not obtained and the state of currentItem does not get advanced - therefore the rendering stops. What I do not understand is why for whatever last view appears on the screen, onLayout is not calling getItemDimensions.

Does anyone have any insight on why the iteration stops, or on a more effective way to achieve my goal? I need to provide getItemLayout to my FlatList as the app needs to be able to ScrollToIndex before a user manually scrolls through the entire FlatList.

Related Questions