Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React-Native (FlatList): How to know when the rendering of visible items has finished

When using a FlatList Component in react native I need to know when all the visible items have been rendered.

I am providing data and the renderItem when I get the componentDidMount I can see the FlatList there but because FlatList Component asynchronously renders each item they only show up after on componentDidUpdate. Also, this could (and probably will) include off-view items.

I would like to know if there is someone out there that has found a possible way to have a controlled process (not with setTimeout) of knowing when the visible items are fully rendered.

Thanks.

like image 748
João Correia Avatar asked Feb 13 '20 14:02

João Correia


People also ask

How do I render FlatList in React Native?

const renderItem = ({ item }) => ( <Item name={item.name} isSelected={item. isSelected} /> ); Display the FlatList React Native component as before… return ( <View style={styles. container}> <FlatList data={countries} renderItem={renderItem} keyExtractor={(item) => item.id} /> </View> );

What is keyExtractor in FlatList?

keyExtractor ​ (item: object, index: number) => string; Used to extract a unique key for a given item at the specified index. Key is used for caching and as the react key to track item re-ordering. The default extractor checks item.key , then item.id , and then falls back to using the index, like React does.


1 Answers

I ended up using the componentDidMount of the renderItem component as an indicator that element is rendered.

In the below example ActivityIndicator will be shown until the first 10 items are rendered (the number I set in the initialNumToRender).

This approach is not ideal. You may need to tweak it for your case but the general idea is shown below.

Here is the list item:

class ListItem extends React.Component<{ onRendered: () => void }> {

  componentDidMount(): void {
    this.props.onRendered();
  }

  render() {
    return (
      <View>
        <Text>Item</Text>
      </View>
    );
  }
}

And here is the screen with FlatList that uses above ListItem:

export class FlatListTestScreen extends React.Component<any, { creating: boolean }> {
  constructor(props: any, context: any) {
    super(props, context);
    this.state = {
      creating: true,
    };
  }

  onRenderedItem = () => {
    this.setState({
      creating: false,
    });
  };

  renderItem = (item: any) => {
    return <ListItem onRendered={this.onRenderedItem} />;
  };

  dataArray = Array(20)
    .fill('')
    .map((_, i) => ({ key: `${i}`, text: `item #${i}` }));

  render() {
    const loader = this.state.creating ? <ActivityIndicator /> : <></>;
    return (
      <View>
        {loader}
        <FlatList
          initialNumToRender={10}
          data={ this.dataArray }
          renderItem={ this.renderItem }
          keyExtractor={ item => item.key }
        />
      </View>
    );
  }
}

I also tried to use a map to collect the number of rendered items but on practice it seems that they all fire componentDidMount at the same time so simpler approach may be better.

like image 108
lub0v Avatar answered Oct 30 '22 20:10

lub0v