Paginating data causing unusual behavior?

Tags: , ,



I am displaying “global posts” on one of my tabs. Currently, there are only 11 posts in the database:

enter image description here

In the app Some of the posts are being duplicated, and I have no idea why these SPECIFIC posts are being duplicated, as it seems to me like it is happening at random.

Here is the code for how I paginate the data.

  1. When the component mounts, I query firestore and pull 5 posts using getCollection().

.

async componentDidMount() {
   
 this.unsubscribe = Firebase.firestore()
.collection('globalPosts')
.orderBy("date_created", "desc")
.limit(5)
.onSnapshot(this.getCollection);  

}
  1. I get the posts successfully in getCollection(), and set an index, lastItemIndex, so I know where to query for the next posts

.

getCollection = (querySnapshot) => {
        const globalPostsArray = [];
        querySnapshot.forEach((res) => {
        const { 
            ..fields
            } = res.data();

            globalPostsArray.push({
                ..fields
            });
        });


        this.setState({
            globalPostsArray,
            isLoading: false, 
            lastItemIndex: globalPostsArray.length - 1
        });
}
  1. This gets the first 5 items, no problem, ordered by date_created, descending.

If the user scrolls down the flatlist, I have logic in the flatlist to handle fetching more data:

            <FlatList
                data={this.state.globalPostsArray}
                renderItem={renderItem}
                keyExtractor={item => item.key}
                contentContainerStyle={{ paddingBottom: 50 }}
                showsHorizontalScrollIndicator={false}
                showsVerticalScrollIndicator={false}
                onRefresh={this._refresh}
                refreshing={this.state.isLoading}
                onEndReachedThreshold={0.5} <---------------------- Threshold
                onEndReached={() => {this.getMore()}} <------------ Get more data
            />
  1. Finally, once it is time to retrieve more data, I call this.getMore()

Here is the code to get the next 5 posts:

getMore = async() => {
    const newPostsArray = [] <-------- new array for the next 5 posts

    Firebase.firestore()
    .collection('globalPosts')
    .orderBy("date_created", "desc")
    .startAfter(this.state.globalPostsArray[this.state.lastItemIndex].date_created) <--- note start after
    .limit(5)
    .onSnapshot(querySnapshot => {
        querySnapshot.forEach((res) => {
            const { 
                ... same fields as getCollection()
                } = res.data();

                newPostsArray.push({
                    ... same fields as getCollection()
                });
            });

            
            this.setState({
                globalPostsArray: this.state.globalPostsArray.concat(newPostsArray), <--- add to state array
                lastItemIndex: this.state.globalPostsArray.length-1 <---- increment index
            });

            console.log(this.state.lastItemIndex) <------- I print out last item index
    })
}

Some notes:

  1. The code works fine in terms of fetching the data

  2. The code works fine in terms of pagination, and only fetches 5 posts at a time

  3. There is no discernible pattern I am seeing in which posts are being duplicated

  4. I am ordering by date_created, descending when querying firestore in both getCollection() and getMore()

  5. I console log “last item index” in my getMore(), and of course the index is higher than the number of posts

  6. I keep getting the following warning/error, with different keys (post ID’s in firestore), which shows me the duplication is happening at random, and not specific to one user. This warning/error doesn’t break the application, but is telling me this weird behavior is happening:

    Encountered two children with the same key, ZJu3FbhzOkXDM5mn6O6T. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

Can someone point me in the right direction, why my pagination is having such unusual behavior?

Answer

My issue was with lastItemIndex. Saving it in state was causing problems. I solved the problem by removing lastItemIndex from state, and making it a local variable in getMore():

getMore = async() => {
    const newPostsArray = []

    const lastItemIndex = this.state.globalPostsArray.length - 1 <---- added it here

    await Firebase.firestore()
    .collection('globalPosts')
    .orderBy("date_created", "desc")
    .startAfter(this.state.globalPostsArray[lastItemIndex].date_created)
    .limit(5)
    .onSnapshot(querySnapshot => {
        querySnapshot.forEach((res) => {
            const { 
                ..fields
                } = res.data();

                newPostsArray.push({
                    key: res.id,
                    ..fields
                });
            });

            
            this.setState({
                globalPostsArray: this.state.globalPostsArray.concat(newPostsArray)
            });

    })
}


Source: stackoverflow