ScrollToEnd after update data for Flatlist

Viewed 17206

I'm making a chat box with Flatlist. I want to add a new item to data then scroll to bottom of list. I use scrollToEnd method but it did not work. How can I do this?

<FlatList
        ref="flatList"
        data={this.state.data}
        extraData = {this.state}
        renderItem={({item}) => <Text style={styles.chatFlatListItem}>{item.chat}</Text>}
/>

AddChat(_chat){
    var arr = this.state.data;
    arr.push({key: arr.length, chat: _chat});
    var _data = {};
    _data["data"] = arr;
    this.setState(_data);
    this.refs.flatList.scrollToEnd();
 }

7 Answers

I found a better solution,scrollToEnd() is not working because it is triggered before the change is made to the FlatList.
Since it inherits from ScrollView the best way here is to call scrollToEnd() in onContentSizeChange like so :

<FlatList
            ref = "flatList"
            onContentSizeChange={()=> this.refs.flatList.scrollToEnd()} /> 

Thanks @Kernael, just add a timeout like so:

setTimeout(() => this.refs.flatList.scrollToEnd(), 200)
const flatList = React.useRef(null)
<FlatList
        ref={flatList}
        onContentSizeChange={() => {
            flatList.current.scrollToEnd();
        }}
        data={this.state.data}
        extraData = {this.state}
        renderItem={({item}) => <Text style={styles.chatFlatListItem}>{item.chat}</Text>}
/>

try this,it works.

Change your code as below. The ref is modified and It's better to use getItemLayout in your FlatList according to this.

AddChat(_chat){
    var arr = this.state.data;
    arr.push({key: arr.length, chat: _chat});
    var _data = {};
    _data["data"] = arr;
    this.setState(_data);
    this.flatList.scrollToEnd();
 }

<FlatList
    ref={elm => this.flatList = elm}
    data={this.state.data}
    extraData = {this.state}
    renderItem={({item}) => <Text style={styles.chatFlatListItem}>{item.chat}</Text>}
    getItemLayout={(data, index) => (
      {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
    )}
/>

Note: Replace the ITEM_HEIGHT with the real value of height of your list items.

  1. Try to use inverted prop on Fatlist itself
  2. Pass your data like this [...data].reverse()
  3. If you are at the middle of list and you need to scroll to end when a new item is added, just use:
    ref  => flatlistRef.current?.scrollToOffset({offset:0})
    

My issue here was that scrollToEnd() worked fine on mobile but on web it always scrolled to the top. Probably because I have elements with different size in the FlatList and couldn't define getItemLayout. But thanks to the accepted answer here I solved it. Just with different approach.

const ref = React.useRef<FlatList>();

function handleScrollToEnd(width, height) {
  if (ref.current) {
    ref.current.scrollToOffset({offset: height});
  }
}

<FlatList
  ref={ref}
  onContentSizeChange={handleScrollToEnd} 
/> 

This works great on both the mobile and web. Hope it helps to somebody.

Related