3

Im trying to implement infinite scroll for React.js. Everything works fine, except I want to be able to use the window scrollbar, to activate the infinite scroll. The code at the moment, has 2 scrollbars( I only want one).

The code is from stackoverflow answered here, I read his complete answer, I tried setting the height to 100%, but it makes the infinite scroll not work. : Stackoverflow- answered by Aniket Jha, ( the longest answer with 4 upvotes)

  • Double scroll happens when I render this in this way:

    <div>
    <First />
     <div ref="iScroll" style={{ height: "100vh", overflow: "auto"}}>
        <ul>
          {this.displayItems()}
        </ul>
        {this.state.loadingState ? <p className="loading"> loading More 
         Items..</p> : ""}
      </div>
    </div>
    

I have a Link to Codepen if this helps

class Layout extends React.Component {
  constructor(props) {
   super(props);
   this.state = {
      items: 30,
      loadingState: false
    };
  }

  componentDidMount() {
    this.refs.iScroll.addEventListener("scroll", () => {
      if (this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >= this.refs.iScroll.scrollHeight - 20){
        this.loadMoreItems();
      }
    });
  }

  displayItems() {
    var items = [];
    for (var i = 0; i < this.state.items; i++) {
      items.push(<li key={i}>Item {i}</li>);
    }
    return items;
  }

  loadMoreItems() {
     if(this.state.loadingState){
         return;
     }
    this.setState({ loadingState: true });
    setTimeout(() => {
      this.setState({ items: this.state.items + 10, loadingState: false });
    }, 1000);
  }

  render() {
    return (<div>

        <First />
          <div ref="iScroll" style={{ height: "100vh", overflow: "auto"}}>
            <ul>
              {this.displayItems()}
            </ul>
            {this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""}
          </div>
        </div>
    );
  }
}

class First extends React.Component {
  constructor(props) {
   super(props);
   this.state = {

    };
  }

  render() {
    return (
      <h1>Testing</h1>

    )
  }
}

ReactDOM.render(<Layout />, document.getElementById('example'));
born2gamble
  • 151
  • 3
  • 15
  • I'm not sure what you mean about "double scrollbars" but I can see that the div is only 200px high. Of course if you set it to 100% then infinite scrolling doesn't work as it's sized too large. I'd suggest trying `height: 100vh`. If I hack it on your codepen, that works well. But then you should also increase the initial number of items — there should be at least 1 more than can fit on the screen. 25 worked for me. – Rajit May 20 '18 at 17:13
  • I updated the codepen. Basically when I am rendering the whole project, the second component being this list, it will give me double scrolls
    – born2gamble May 20 '18 at 18:38

1 Answers1

1

If you don't want the second scrollbar to appear, you need to style the title and sibling div so that they fit in the available viewport.

In your codepen, you have height: '100%' for your scrolling div. This styles the div so that it doesn't need to scroll and infinite scroll therefore doesn't work.

If you style that div so that it takes up less than the height of the available viewport, and render enough items to fill it up, infinite scroll will work fine.

If you then style the title div combination so that they fit exactly into the available viewport space, you won't get a second scrollbar.

Below is an option you have to do this. What I've done is set the height of the scrolling div to be the viewport height (100vh) minus 100px. That's not precisely calculated, but what you want is to subtract the space required for the title from the size of the viewport.

This implementation works fine for me, and should for you as well.

class Layout extends React.Component {
  constructor(props) {
   super(props);
   this.state = {
      items: 30,
      loadingState: false
    };
  }

  componentDidMount() {
    this.refs.iScroll.addEventListener("scroll", () => {
      if (this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >= this.refs.iScroll.scrollHeight - 20){
        this.loadMoreItems();
      }
    });
  }

  displayItems() {
    var items = [];
    for (var i = 0; i < this.state.items; i++) {
      items.push(<li key={i}>Item {i}</li>);
    }
    return items;
  }

  loadMoreItems() {
  if(this.state.loadingState){
   return;
  }
    this.setState({ loadingState: true });
    setTimeout(() => {
      this.setState({ items: this.state.items + 10, loadingState: false });
    }, 1000);
  }
  
  render() {
    return (<div>
     
        <First />
          <div ref="iScroll" style={{ height: "calc(100vh - 100px)", overflow: "auto"}}>
            <ul>
              {this.displayItems()}
            </ul>
            {this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""}
          </div>
        </div>
    );
  }
}

class First extends React.Component {
  constructor(props) {
   super(props);
   this.state = {
    
    };
  }

  render() {
    return (
      <h1>Testing</h1>

    )
  }
}

ReactDOM.render(<Layout />, document.getElementById('example'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="example"></div>
Rajit
  • 788
  • 4
  • 8
  • Is it possible to have component not fixed at the top. So when I scroll down I dont see it anymore, and it still populates as I reach the bottom? – born2gamble May 20 '18 at 19:41
  • 1
    Yes, absolutely. But in that case you'll need to move the `ref="iScroll"` to the parent `div` and also move the `style` attribute there. Let me know if you have problems, I can update the answer if you need – Rajit May 20 '18 at 19:46
  • Got it to work with your help, thanks for teaching me the logic in this, it helped alot. – born2gamble May 20 '18 at 19:57