Prepending data to a FlatList always shows the first child

Viewed 5301

this is our FlatList, say hello:

<FlatList
    data={this.state.dates}
...
/>

we feed it with the following dates:

this.state = {
    dates: [
        '21/06/2019',
        '22/06/2019',
        '23/06/2019',
    ]
};

then when the visible date changes (onViewableItemsChanged), if we end up to the first item (21/06/2019), we prepend data, so that the new state becomes:

dates: [
        '18/06/2019',
        '19/06/2019',
        '20/06/2019',
        '21/06/2019',
        '22/06/2019',
        '23/06/2019',
]

The Problem:

right after we prepend the data, instead of STILL seeing 21/06/2019 (which was the date when the prepend took place) we now see 19/06/2019.

That's because below the hood, 21/06/2019 used to be index 0, but after the prepend, index 0 corresponds to 19/06/2019.

What we want:

I'm trying to make it so that the day remains the same after prepending data.

Please don't tell me to use scrollToPosition because that's a hack really, not the solution. Is there any good solution to that problem?

Thank you

4 Answers

There is an undocumented prop maintainVisibleContentPosition on ScrollView that do what you want, but unfortunately it's not working on android

I found another workaround by keep latest y offset with onScroll and also save content height before and after adding new items with onContentSizeChange and calculate the difference of content height, and set new y offset to the latest y offset + content height difference!

I've opened an issue on github also, but there is not any complete solution yet
Thanks to sgtpepper43 for undocumented iOS solution

that maintainVisibleContentPosition does not work if you prepend data while you are at a scroll position of 0 (all the way to the top). It does work if you are prepending while not a the top. Even scroll Y of 1 would be enough.

check this

Unfortunately this still an issue even in React Native 0.63.3 and has not been solved.

Leaving this here, since it took me a while to get a working solution/ workaround to this problem that doesn't leave a bad taste in my mouth: prepopulate the array with empty data, and then use the scrollToIndex method.

this.state = {
  dates: [
    '',
    '',
    '',
    '21/06/2019',
    '22/06/2019',
    '23/06/2019',
  ]
};

And then:

<FlatList
    data={this.state.dates}
    ref={flatListRef}
    getItemLayout={(data, index) => (
      {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
    )}
...
/>

inside your componentDidMount:

const startingIndex = 4
flatListRef.current.scrollToIndex({index: startingIndex, animated: false, viewPosition: 0})

There's a library: https://github.com/GetStream/react-native-bidirectional-infinite-scroll that allows you to both preprend or append data and preserve scroll position

It's basically an extension over the FlatList and supports all the props available for a plain FlatList

From their example usage tutorial: https://dev.to/vishalnarkhede/react-native-how-to-build-bidirectional-infinite-scroll-32ph#%F0%9F%96%A5-tutorial-chat-ui-with-bidirectional-infinite-scroll

It looks like it would be enough to just prepend that data to the top exactly like you're trying to do

Related