0

My plan is to load data when you scroll and reach the bottom of the page. I am using JQuery scroll to make it possible and it works fine if no data to display (just console log the data). But if I start displaying data, the scroll fire twice or something else firing twice which I do not know what. Here is my code:

import React from 'react';

class UsersBrowse extends React.Component {
  render() {
    let x = this.props;
    $(window).unbind('scroll').scroll(function() {
      if($(window).scrollTop() + $(window).height() == $(document).height()) {
        const {loadMore, currentPage} = x;
        loadMore(currentPage);
      }
    });
    const {scanUserResult, loading} = this.props;
    console.log(this.props);
    return (
      <div>
        {scanUserResult ? scanUserResult.map(users => (
          <div key={users._id}>
            <div>{users._id}</div>
          </div>
        )):<img src={loading} height="100" width="100" />}
      </div>
    );
  }
}

export default UsersBrowse;

The code works fine if I just console log the data but when I display it on the page it skips like:

loads page 1 skip page 2 loads page 3 skip page 4 loads page 5

My expectation is, it should load:

page1 page2 page3 page4

It works if I do it like this:

import React from 'react';

class UsersBrowse extends React.Component {
  render() {
    const {scanUserResult, loading} = this.props;
    let x = this.props;
    $(window).unbind('scroll').scroll(function() {
      if($(window).scrollTop() + $(window).height() == $(document).height()) {
        const {loadMore} = x;
        loadMore();
      }
    });
    console.log(this.props);
    return (
      <div>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
        test<br/>
      </div>
      // <div>
      //   {scanUserResult ? scanUserResult.map(users => (
      //     <div key={users._id}>
      //       <div>{users._id}</div>
      //     </div>
      //   )):<img src={loading} height="100" width="100" />}
      // </div>
    );
  }
}

export default UsersBrowse;

Any idea? Thank you

3 Answers3

0

I think it's because there are two times $(window).scrollTop() + $(window).height() == $(document).height(), so it trigger twice. maybe you can set a flag for it.

static loading = true;
render() {
    let x = this.props;
    $(window).unbind('scroll').scroll(function() {
      if($(window).scrollTop() + $(window).height() == $(document).height() && loading == true) {
       loading = false;
        const {loadMore, currentPage} = x;
        loadMore(currentPage);
      }
    });
    const {scanUserResult, loading} = this.props;
    console.log(this.props);
    return (
      <div>
        {scanUserResult ? scanUserResult.map(users => (
          <div key={users._id}>
            <div>{users._id}</div>
          </div>
        )):<img src={loading} height="100" width="100" />}
      </div>
    );
  }
chenkehxx
  • 1,589
  • 12
  • 15
  • thank you so much for the response let me try it a min – Jagmok Dugmok Jun 28 '16 at 02:30
  • I did the flag combined with **componentDidMount** . . it works on the first scroll, the data count came out as expected; however, the data does not load on the second scroll. My guess is because the the **loading** variable is now **false**. I thought the loading will become **true** again if I scroll back. Is there a way to trigger the **componentDidMount** ? – Jagmok Dugmok Jun 28 '16 at 03:28
  • you should set the flag to be true in your loadMor function. after you get the next page data, just set it to be true. – chenkehxx Jun 28 '16 at 03:35
0

My guess (I would need to view the entire code to confirm) is that when your content is being rendered, it is making your page bigger (increasing the height), when your page grows, the scroll event will be fired, making your component re-render (I would need to check your code to see the relation between your props and etc.) and logging things in your console.

You just need to orchestrate it better, sometimes a timeout may help, or some kind of "loading" state, or you may "lock" the scroll event until component re-renders.

Just a tip, it is not a good pattern to bind events on render. You can use componentDidMount and componentWillUnmount in this case.

William Martins
  • 1,969
  • 1
  • 18
  • 22
  • The **componentDidMount** works combined with what **chenkehxx** suggestion about the flagging to prevent the scroll from firing twice. Now it only works on the first scroll. Is there a way to trigger the **componentDidMount** back? – Jagmok Dugmok Jun 28 '16 at 03:30
  • Well, you should first remove the `unbind` scroll from render, and move it to `componentWillUnmount`. This way your scroll event will be handled correctly. The only thing you will need to do is handle the next page using a state or a prop. But I think putting the `unbind` in the correct place will make it work. – William Martins Jun 28 '16 at 04:08
0

Finally sorted it out by adding it inside componentWillMount and then set a timeout of 200ms.

Infinite scroll fired twice on refresh from the bottom of page

Code goes like this:

import React from 'react';

class UsersBrowse extends React.Component {
  componentWillMount() {
    let x = this.props;
    let timeout;
    $(window).scroll(function(){
      clearTimeout(timeout);
      timeout = setTimeout(function(){
        if($(window).scrollTop() + $(window).height() == $(document).height()) {
          const {loadMore} = x;
          loadMore();
        }
      }, 200);
    });
  }

  render() {
    const {scanUserResult, loading} = this.props;
    console.log(this.props);

    return (
      <div>
        {scanUserResult ? scanUserResult.map(users => (
          <div key={users._id}>
            <div>{users._id}</div>
          </div>
        )):<img src={loading} height="100" width="100" />}
      </div>
    );
  }

}

export default UsersBrowse;

Resolved :D

Community
  • 1
  • 1