react-infinite-scroller
react-infinite-scroller copied to clipboard
loadmore twice
From https://github.com/guillaumervls/react-infinite-scroll/issues/44:
Every time the loadmore event is triggered, it triggers two times
same issue
Same for me. I don't know if ithassomethingto do with first "bottom"in the browser where there is no appended itemsyet.
It's okay because it tries to resolve the free space and draw the scrollbar for future scrolling. Otherwise, you will be not able scroll more data.
Given you want 1 item per page, InfiniteScroll will be trigger loadMore 10 times. Given you want 5 item per page, InfiniteScroll will be trigger loadMore 2 || 3 times, regarding wrappers filled percentage. But, if you want 10 item per page, and InfiniteScroll triggering loadMore 2 || 3 times, so it's for safety. But if you want 20 item per page, maybe calculating will be 1 loadMore.
In your code screenshot, there is another problem, how I can see, you passing to hasMore only true, imagine now what will happen, if API will return only 1 item, or 2, or less than you want, in the case when you wanted 10.
It will be an infinite loop of requests! So fix it and don't worry about one more request.
Same issue
Let say I have an API callback in loadMore() so sometimes it is being called more than once for the same page. The problem is not about just one more request because it is easily reproducible, so it will cost you a lot more than that.
@danial-iqbal-confiz do you use loadMore's page or managing page in your own component state?
And maybe it's OPTIONS request? One time I confused, because on Network tab there are a lot of requests with GET and with OPTIONS.
@hosembafer Your answer isn't clear as to why this issue should be ignored. From my perspective if a request is already in progress then we should we block all other infinite-scroll requests until it's resolved or rejected, their's no reason to overload the server with multiple useless calls that do the same thing.
I solved this by setting a boolean flag to true in the API callback so that only 1 request is sent at a time.
@devendra-gh You don't need setTimeout
. Just toggle a boolean flag in your API callback to know when the request is done.
Same behaviour for me... load more is being triggered twice in parallel.
Same issue here
Triggered multiple times...
@ttt43ttt Did you try any of the workarounds listed above? That's the only way to stop it currently.
The page
argument passed in function handleLoadMore(page)
is not correct either.
But finally, there is workaround. I have to manage the state by myself.
@CassetteRocks, I think this problem related to documentation. Component only have hasMore prop to control this case, but what about in progress state, when you have more items to fetch, but you need to stop fetching by hasMore=false, maybe you need to add isFetching prop, or just write complex example in README.md like hasMore={hasMore && !isFetching}
I think that setTimeout isn't a good decision. For me I have just wrote wrapper with state to handle this.
@MartinDawson can you tell me where toggle boolean flag in API, i'm confusing in it where and what flag would be toggle in my code
Same issue :|
here is working fix of issue with triggering loadMore
twice
<InfiniteScroll
hasMore={!isLoading}
...
/>
where isLoading
is true when you request API and false when request is done.
I recently updated the issue templates on this repo so that I can identify the bugs with this repo.
Please clone your layout and use of react-infinite-scroller by forking this Code Sandbox and linking it here. Doing so will massively expedite getting the bug fixed! 👊
export const fetchAsync = (page, cate) => {
return (dispatch) => {
// first update redux state
dispatch(fetchStarted(cate));
axios.get('http://result.eolinker.com/xULXJFG7a8d149be1ed30d8132092c1987f99b9ee8f072d?uri=exchange_record')
.then((response) => {
// second update redux state
dispatch(fetchSuccess(cate, response.data.list));
})
.catch((error) => {
dispatch(fetchFailure(cate, error));
})
.finally(() => {
});
};
};
use redux async action and react-infinite-scroller bring loadmore twice
@ApacheEx this cannot be done if child components are themselves making API request
if you use redux or mobx then it can be done 😋
Set threshold
to a small value like 20 solved for me.
here is working fix of issue with triggering
loadMore
twice<InfiniteScroll hasMore={!isLoading} ... />
where
isLoading
is true when you request API and false when request is done.
this is a bad fix, by doing this the loading indicator is no longer shown, and also when the end of the list is reached the loadMore function is triggered indefinitely.
you're right, it should be more like this:
<InfiniteScroll
hasMore={!isLastPage && !isLoading}
...
/>
where:
-
isLoading
is true when you request API and false when request is done. -
isLastPage
is true when the last page of API reached otherwise false.
p.s I'm using another library / component for loading indicator.
@ApacheEx I've ended keeping the state myself.
the loadFunc exists if there's an inflight request. page tracking is also kept in my redux store, at the next request i'm incrementing page+1
loadFunc = () => {
const {isFetchingPage, page} = this.props
if (isFetchingPage) {
return;
}
this.props.fetchData(page+1)
}
and in render function has_more - is received from the backend pagination response.
<InfiniteScroll className='flex-child p30'
pageStart={1}
loadMore={this.loadFunc}
hasMore={has_more}
loader={loader}
>
too bad this component has 42,980 active weekly downloads, and it's not maintained 😞
my modification
Original (https://github.com/CassetteRocks/react-infinite-scroller/blob/ce7ce556a10f91df52323a2b002bec6a0db23652/src/InfiniteScroll.js#L35)
constructor(props) {
super(props);
this.scrollListener = this.scrollListener.bind(this);
}
Edit
constructor(props) {
super(props);
this.scrollListener = debounce(this.scrollListener.bind(this), 100)
}
debounce example https://www.npmjs.com/package/lodash.debounce
if above is not enough, more strictly
in scrollListener function
Original (https://github.com/CassetteRocks/react-infinite-scroller/blob/ce7ce556a10f91df52323a2b002bec6a0db23652/src/InfiniteScroll.js#L176)
if (typeof this.props.loadMore === 'function') {
Edit
if (typeof this.props.loadMore === 'function' && this.props.hasMore) {
It' simple, please add variable name as page = 1 Code sample:
page = 1;
constructor(props) {
super(props);
this.state = {
tracks: [],
hasMoreItems: true,
result_limit: 5
};
}
loadItems() {
NoticesRequest.fetchListNotice({
result_limit: this.state.result_limit,
page: this.page
}).then(resp => {
resp.data.map((track) => {
this.state.tracks.push(track);
});
this.page = this.page + 1;
if (resp.data.length < this.state.result_limit) {
this.setState({
hasMoreItems: false
});
}
});
}
renderItem() {
let items = [];
this.state.tracks.map((track, i) => {
items.push(
<div className="row track" key={i}>
<p className="title">{track.incident_time}</p>
</div>
);
});
}
render() {
return (
<InfiniteScroll
pageStart={0}
loadMore={this.loadItems.bind(this)}
hasMore={this.state.hasMoreItems}
loader={<div key={this.page} className="loader">Loading ...</div>}
>
<div className="tracks">
{this.renderItem()}
</div>
</InfiniteScroll>
);
}
same issue here