New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FlatList onEndReached triggered before reach onEndReachedThreshold #12827

Closed
alphasp opened this Issue Mar 9, 2017 · 40 comments

Comments

Projects
None yet
@alphasp
Copy link

alphasp commented Mar 9, 2017

Description

FlatList onEndReached triggered before reach end of list. If legacyImplementation is set to true or render with ListView, onEndReached will trigger correctly when it reached end of list

Reproduction

Based from FlatListExample on UIExplorer in React Native v0.43.0-rc.1, add onEndReached to FlatList

state = {
  data: genItemData(30),
  debug: false,
  horizontal: false,
  filterText: '',
  fixedHeight: true,
  logViewable: false,
  virtualized: true,
};

<FlatList
  HeaderComponent={HeaderComponent}
  FooterComponent={FooterComponent}
  SeparatorComponent={SeparatorComponent}
  data={filteredData}
  debug={this.state.debug}
  disableVirtualization={!this.state.virtualized}
  getItemLayout={this.state.fixedHeight ?
    this._getItemLayout :
    undefined
  }
  horizontal={this.state.horizontal}
  key={(this.state.horizontal ? 'h' : 'v') +
    (this.state.fixedHeight ? 'f' : 'd')
  }
  legacyImplementation={false}
  numColumns={1}
  onRefresh={this._onRefresh}
  onViewableItemsChanged={this._onViewableItemsChanged}
  ref={this._captureRef}
  refreshing={false}
  renderItem={this._renderItemComponent}
  shouldItemUpdate={this._shouldItemUpdate}
  viewabilityConfig={VIEWABILITY_CONFIG}
  onEndReachedThreshold={1}
  onEndReached={({ distanceFromEnd }) => {
    console.log('on end reached ', distanceFromEnd)
  }}
/>  

Additional Information

  • React Native version: v0.43.0-rc.1
  • Platform: Both
  • Operating System: MacOS

@alphasp alphasp changed the title FlatList onEndReached trigger before reach end of list FlatList onEndReached triggered before reach end of list Mar 9, 2017

@ramilushev

This comment has been minimized.

Copy link

ramilushev commented Mar 10, 2017

@alphasp I have not yet played around with FlatList, but is there any chance that the onEndReachedThreshold has some default non-zero value you are unaware of?

@alphasp

This comment has been minimized.

Copy link

alphasp commented Mar 10, 2017

@ramilushev Yes, just checked the code, created a PR to make it behave like ListView implementation

@alphasp

This comment has been minimized.

Copy link

alphasp commented Mar 13, 2017

@sahrens Can you have a look at this issue and my pull request?

@sahrens

This comment has been minimized.

Copy link
Contributor

sahrens commented Mar 14, 2017

What if you set the threshold to zero?

@alphasp

This comment has been minimized.

Copy link

alphasp commented Mar 14, 2017

@sahrens If onEndReachedThreshold is set to zero, onEndReached will be trigger when reach end of list. However if the threshold is set to more than 0, for example 10, onEndReached will be trigger before it go past the threshold value due to this line
https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Lists/VirtualizedList.js#L591
where you compare distanceFromEnd < onEndReachedThreshold * visibleLength
On my iPhone 7 Simulator, when running the FlatListExample, the values will be distanceFromEnd < 10 * 504.5, which will trigger onEndReached immediately before it go past the threshold value

@alphasp alphasp changed the title FlatList onEndReached triggered before reach end of list FlatList onEndReached triggered before reach onEndReachedThreshold Mar 14, 2017

@liyonghui16

This comment has been minimized.

Copy link

liyonghui16 commented Mar 23, 2017

I also encountered this problem, hope the next version can fix it.

@rqzheng2015

This comment has been minimized.

Copy link

rqzheng2015 commented Mar 27, 2017

I know how to solve this, you just need to set onEndReachedThreshold as a rate of visibleLength.
So you just need to set it as a number smaller than 1, then it worked!!!!!

@grundmanise

This comment has been minimized.

Copy link

grundmanise commented Mar 30, 2017

If onEndReachedThreshold > 0 then it is triggered 2 times..

@sahrens

This comment has been minimized.

Copy link
Contributor

sahrens commented Mar 30, 2017

The denouncing is based on state changes, so if you rerender anything or update the data in response to the callback or after it's called the first time, it might get called again.

@thiensubs

This comment has been minimized.

Copy link

thiensubs commented Apr 3, 2017

My error in Production:

com.facebook.react.common.JavascriptException: undefined is not a function (evaluating 't._ItemLoadMore()'), stack:
onEndReached@574:4466
_onScroll@277:16504
scrollResponderHandleScroll@263:1975
_handleScroll@261:2584

I think EndReached has problem.

@sahrens

This comment has been minimized.

Copy link
Contributor

sahrens commented Apr 4, 2017

@thiensubs It looks like you're providing a callback that may not be correctly bound so not sure what would be wrong with FlatList. Do you have more sample code that shows what you're doing and may reveal the bug?

@thiensubs

This comment has been minimized.

Copy link

thiensubs commented Apr 4, 2017

@sahrens My Flatlist like this:

 var flatList = <FlatList
                style={styles.lStyle }
                data={this.state.dataSource2}
                renderItem={ItemRowYesterdaySignal.bind(this)}
                onEndReachedThreshold={10}
                onEndReached={({ distanceFromEnd }) => {
                   this._ItemLoadMore();
                }}
                ref='_flatList'
            />;
_ItemLoadMore(){
        if (this.state.current_page +1 <= this.state.total_pages)
        {
            if (this.keyword  && this.keyword !='')
            {
                var page = this.state.current_page+1;
                this.search(this.keyword, page)
            }
            else
            {
                this.loadMore(this.state.current_page+1)
            }
        }
    }

Thanks for your comment.

@sahrens

This comment has been minimized.

Copy link
Contributor

sahrens commented Apr 4, 2017

Can you provide more context including the lifecycle of the component that renders the FlatList and where you use the ref?

@thiensubs

This comment has been minimized.

Copy link

thiensubs commented Apr 4, 2017

Yes. It like pagination, when I scroll to onEndReachedThreshold 10, it will call LoadMore, it repeat again with condition
this.state.current_page +1 <= this.state.total_pages
I don't use ref any where, I just define that.
Do you need image for list?

huston007 added a commit to JetBrains/youtrack-mobile that referenced this issue Apr 6, 2017

@jjdp

This comment has been minimized.

Copy link

jjdp commented Apr 15, 2017

also encountering this problem

@narek11

This comment has been minimized.

Copy link

narek11 commented Apr 22, 2017

same problem here

@kesha-antonov

This comment has been minimized.

Copy link

kesha-antonov commented Apr 28, 2017

+1 !!!
I scroll a little bit and "onEndReached" called already. ListView did not have that problem!

I just replaced ListView with FlatList. All props and code the same.

@sahrens

@alphasp

This comment has been minimized.

Copy link

alphasp commented Apr 28, 2017

onEndReachedThreshold?: ?number

How far from the end (in units of visible length of the list) the bottom edge of the list must be from the end of the content to trigger the onEndReached callback. Thus a value of 0.5 will trigger onEndReached when the end of the content is within half the visible length of the list.

As quoted in updated doc regarding onEndReachedThreshold on http://facebook.github.io/react-native/releases/0.44/docs/flatlist.html#onendreachedthreshold
We will need to set value range from 0 to 1 where value of 0.5 will mean half the visible length of the list

@alphasp alphasp closed this Apr 28, 2017

@msqar

This comment has been minimized.

Copy link

msqar commented May 19, 2017

So on every onEndReached event i'm increasing my page number by 1. Would this be considered normal in a common app? or should I stop increasing the number if there are no more results to fetch?

Also, I noticed the when scrolling back up, sometimes endReached gets called again...

@idibidiart

This comment has been minimized.

Copy link

idibidiart commented May 19, 2017

@msqar no you have to pick a value between 0 and 1 and stick to it. It's about when FlatList will get the new data, i.e, how far into the current view before it goes and get new data. 0 is the start and 1 is the end. When you get to the end and your Threshold is 1 it will get more data and at that point you're back at 0. It would be odd if the designers of FlatList expected the user to increment the threshold.

@msqar

This comment has been minimized.

Copy link

msqar commented May 19, 2017

@idibidiart Ok, i will set it somewhere between 0.5 and 0.8. But is it good to have the page increasing by one all the time unless you pull up to refresh which resets it to 1 again? Or should i implement it differently?

@idibidiart

This comment has been minimized.

Copy link

idibidiart commented May 19, 2017

0.5 - 0.8 sounds good ... try to make any data processing loop asynchronous, e.g. with requestAnimationFrame (async re-entrant loop) so it does not hold up the list scrolling while you're transforming the data, that is if you have ay transforming to do.

What do you mean by page increasing by one all the time? The threshold should have nothing to do with the page number.

Maybe I'm missing something?

@msqar

This comment has been minimized.

Copy link

msqar commented May 19, 2017

@idibidiart I'm doing infinite scrolling (pagination) and using FlatList. Page is just a state value I have to determine what page number is going to be sent to the REST API. And onEndReached event I just increase the page number by 1. That way it keeps sending the pages to my app. But I noticed that whenever i scrolled at max and got all the pages from DB, if i start to scroll up, the endReached event is called again with no reason... is that normal?

@idibidiart

This comment has been minimized.

Copy link

idibidiart commented May 19, 2017

I assume that when using FlatList you need to keep the current materialized view's data and some buffer above it and below it, or else if you will run out of memory eventually. The event firing makes sense but the way tou handle it is up to you. FlatList is not fetching the data for you. It just tells you when the current Threshold has been reached, in either direction. Makes sense to me. I have to admit I just got to play with FlatList and have not used it in any real scenario yet.

Does this help?

@msqar

This comment has been minimized.

Copy link

msqar commented May 19, 2017

@idibidiart yes :) then i think is fine then! Thanks!

@grin

This comment has been minimized.

Copy link

grin commented Jun 23, 2017

For folks reporting the onEndReached callback being called twice on iOS, this may be caused by the ScrollView bouncing effect, as described in this thread: #14015

I also posted my solution there.

@vvavepacket

This comment has been minimized.

Copy link

vvavepacket commented Aug 6, 2017

i tried setting onEndReachedThreshold to 0.5,, now I'm halfway of my flat list, and onEndReached() is not triggered, i tried scrolling past it, reaching the very end of the list, still the onEndReached() is not triggered.

Why is it not working on android?

<Content>
                       <FlatList
                           data={this.props.destination_place_list}
                           renderItem={this.renderItem}
                           keyExtractor={item => item.id}
                           onEndReached={(xxx) => {
                                   console.log(xxx);
                                   this.handleLoadMore.bind(this);
                               }
                           }
                           onEndReachedThreshold={0.5}
                       />
</Content>

I'm using android and react-native 0.45. Have you guys fixed the issue?

@idibidiart

This comment has been minimized.

Copy link

idibidiart commented Aug 6, 2017

I believe Content is from NativeBase and I believe that implements a ScrollView. FlatList cannot work right inside a ScrollView.

@amin3mej

This comment has been minimized.

Copy link
Contributor

amin3mej commented Oct 11, 2017

@idibidiart I have this problem in my code and how i can fix it ? tnx

@halzahrani79

This comment has been minimized.

Copy link

halzahrani79 commented Oct 13, 2017

I have this problem too it really needs to be fixed , it really drive me crazy ! (and yes i used it inside the Container component from NativeBase )

@vigor87

This comment has been minimized.

Copy link

vigor87 commented Oct 24, 2017

Is there any function called when scroll reached start. Something like onStartReached() ???

@maurolionel

This comment has been minimized.

Copy link

maurolionel commented Oct 24, 2017

@vigor87 What are you trying to achieve? I'm using the onScroll prop on FlatList and saving it's scroll-y value into a React.Component's state to decide whether to show an image shadow or not. When the scroll-y value is 0 the shadow is displayed with no opacity at all.

@mschipperheyn

This comment has been minimized.

Copy link

mschipperheyn commented Nov 1, 2017

I'm noticing that when using onEndReached to load more content and there is no more content, but the data array is changed (because loading nothing lead to a new identical array being created) and therefore a rerender is triggered with the cursor position is at the end, onEndReached is called again and an infinite loop occurs. I would suggest that onEndReached only gets triggered during or after scrolling.

@jing-wu

This comment has been minimized.

Copy link

jing-wu commented Nov 23, 2017

Try this
onEndReachedThreshold={0.01}

@priyankinfinnov

This comment has been minimized.

Copy link

priyankinfinnov commented Dec 3, 2017

@vigor87 did you find onStartReached() ?

@maurolionel

This comment has been minimized.

Copy link

maurolionel commented Dec 4, 2017

@priyankinfinnov have you tried using onScroll?

@jbaek7023

This comment has been minimized.

Copy link

jbaek7023 commented Dec 20, 2017

I understand @sahrens 's comment "The denouncing is based on state changes, so if you rerender anything or update the data in response to the callback or after it's called the first time, it might get called again."

But how can we prevent it from calling onEndReached when it's re-rendered???

return (
  <View style={{ flex:1 }}>
    <FlatList
      data={this.props.categories}
      renderItem={this._renderItem}
      keyExtractor={this._keyExtractor}
      numColumns={2}
      style={{flex: 1, flexDirection: 'row'}}
      contentContainerStyle={{justifyContent: 'center'}}
      refreshControl={
        <RefreshControl
          refreshing = {this.state.refreshing}
          onRefresh = {()=>this._onRefresh()}
        />
      }
      // curent value for debug is 0.5
      onEndReachedThreshold={0.5} // Tried 0, 0.01, 0.1, 0.7, 50, 100, 700

      onEndReached = {({distanceFromEnd})=>{ // problem
        console.log(distanceFromEnd) // 607, 878 
        console.log('reached'); // once, and if I scroll about 14% of the screen, 
                             //it prints reached AGAIN. 
        this._onEndReachedThreshold()
      }}
    />
  </View>
)

More:
https://stackoverflow.com/questions/47910127/flatlist-calls-enendreached-when-its-rendered

@uc-asa

This comment has been minimized.

Copy link

uc-asa commented Jan 17, 2018

Hi,

Please check if you are using minimum value in an array because I had faced this issue and correct.

@AyubaMakoa

This comment has been minimized.

Copy link

AyubaMakoa commented Jan 30, 2018

`constructor(props){
super(props);
this.state = {
flatListReady:false
}
}

_scrolled(){
this.setState({flatListReady:true})
}

loadMore = () => {
if(!this.state.flatListReady){ return null}

//you can now load more data here from your backend

}
<FlatList
onScroll={this._scrolled.bind(this)}
style={{width:'100%',flexGrow:1}}
ListHeaderComponent={this.headerComponent}
data={this.props.data}
renderItem={this.renderItem}
keyExtractor={(item,index) => index }
onEndReached={(x) => {this.loadMore()}}
onEndReachedThreshold={0.5}

       />

`

@Suraj-Tiwari

This comment has been minimized.

Copy link

Suraj-Tiwari commented Feb 17, 2018

Ok so in my case issue was because I was using Listview inside Content from NativeBase using it inside Container fixed the issue

@facebook facebook locked as resolved and limited conversation to collaborators May 24, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.