react-infinite-scroller icon indicating copy to clipboard operation
react-infinite-scroller copied to clipboard

loadmore twice

Open isaak-zmg opened this issue 6 years ago • 46 comments

From https://github.com/guillaumervls/react-infinite-scroll/issues/44:

Every time the loadmore event is triggered, it triggers two times

image

image

isaak-zmg avatar Mar 12 '18 13:03 isaak-zmg

same issue

ess3nt avatar Mar 13 '18 22:03 ess3nt

Same for me. I don't know if ithassomethingto do with first "bottom"in the browser where there is no appended itemsyet.

rodrigobutta avatar Mar 18 '18 06:03 rodrigobutta

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.

hosembafer avatar Mar 23 '18 16:03 hosembafer

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.

hosembafer avatar Mar 23 '18 16:03 hosembafer

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 avatar Mar 28 '18 07:03 danial-iqbal-confiz

@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 avatar Mar 28 '18 09:03 hosembafer

@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.

MartinDawson avatar Mar 31 '18 15:03 MartinDawson

@devendra-gh You don't need setTimeout. Just toggle a boolean flag in your API callback to know when the request is done.

MartinDawson avatar Apr 02 '18 14:04 MartinDawson

Same behaviour for me... load more is being triggered twice in parallel.

julensas avatar Apr 06 '18 08:04 julensas

Same issue here

pcc1650 avatar Apr 06 '18 10:04 pcc1650

Triggered multiple times...

ttt43ttt avatar Apr 15 '18 11:04 ttt43ttt

@ttt43ttt Did you try any of the workarounds listed above? That's the only way to stop it currently.

MartinDawson avatar Apr 15 '18 11:04 MartinDawson

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.

ttt43ttt avatar Apr 15 '18 11:04 ttt43ttt

@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}

hosembafer avatar Apr 15 '18 14:04 hosembafer

I think that setTimeout isn't a good decision. For me I have just wrote wrapper with state to handle this.

mykolavlasov avatar Apr 20 '18 08:04 mykolavlasov

@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

himrah avatar May 03 '18 05:05 himrah

Same issue :|

dthtien avatar May 05 '18 15:05 dthtien

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.

ApacheEx avatar May 07 '18 10:05 ApacheEx

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! 👊

danbovey avatar May 14 '18 19:05 danbovey


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

refanbanzhang avatar Jul 25 '18 03:07 refanbanzhang

@ApacheEx this cannot be done if child components are themselves making API request

armujahid avatar Aug 17 '18 11:08 armujahid

if you use redux or mobx then it can be done 😋

ApacheEx avatar Aug 17 '18 13:08 ApacheEx

Set threshold to a small value like 20 solved for me.

dylan-shao avatar Aug 29 '18 22:08 dylan-shao

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.

mihaiserban avatar Sep 17 '18 10:09 mihaiserban

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 avatar Sep 17 '18 11:09 ApacheEx

@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}
          >

mihaiserban avatar Sep 17 '18 13:09 mihaiserban

too bad this component has 42,980 active weekly downloads, and it's not maintained 😞

mihaiserban avatar Sep 17 '18 13:09 mihaiserban

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) {

ta-toshio avatar Nov 01 '18 01:11 ta-toshio

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>
    );
}

dienchainos avatar Jan 10 '19 23:01 dienchainos

same issue here

PerlBug avatar Jan 15 '19 06:01 PerlBug