Search code examples
javascriptreactjsscroll

What is the best way to get document scroll percentage in react app?


I would like to know when the user is nearing the bottom of the document so I can fetch the next page of data from the API.

I currently have this snippet which I am using to get scroll position and total document height but something is off as when user is at the bottom of page, it shows 88% scrolled down page.

addScrollListener(){
    window.addEventListener('scroll', debounce(() => {// lodash debounce method.
        let supportPageOffset = window.pageXOffset !== undefined;
        let isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat');
        let scroll = {
           x: supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft,
           y: supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop
        };

        console.log('scroll.y', scroll.y)
        console.log('offsetHeight', document.documentElement.offsetHeight)

        let scrollPercentage = (scroll.y / document.documentElement.offsetHeight) * 100

        console.log('scrollPercentage', scrollPercentage)

        if(scrollPercentage > 88){ 
           this.props.fetchData(`https://www.reddit.com/r/funny/${this.state.filter}.json?after=${this.props.after}`, this.props.posts)
        }
        }, 300));//ms
  }

When I the user is at the bottom of the page, the console.log values are as follows:

scroll.y 5222
offsetHeight 5921
scrollPercentage 88.1945617294376

Any idea what is causing this discrepancy?

Or is there a better way of detecting scroll percentage in react?

Alternatively perhaps there is a better way to trigger the fetch next page call rather than using scroll percentage?

Thanks in advance.

EDIT:

The working solution -

addScrollListener(){
    window.addEventListener('scroll', debounce(() => {// lodash debounce method.
        let supportPageOffset = window.pageXOffset !== undefined;
        let isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat');
        let scroll = {
           x: supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft,
           y: supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop
        };

        let scrollPercentage = (scroll.y / (document.documentElement.offsetHeight - window.innerHeight)) * 100

        if(scrollPercentage > 90){ 
           this.props.fetchData(`https://www.reddit.com/r/funny/${this.state.filter}.json?after=${this.props.after}`, this.props.posts)
        }
        }, 300));//ms
  }

Solution

  • Let's suppose you have a screen of X in height and a document of Y in height, Y >= X.

    In this case, at position 0, the bottom position of the screen is X and when you scroll to the very bottom position in the document, the bottom position seen in the screen is Y and the top of the scroll position is Y - X.

    So, when you calculate the percentage, when you are say, at position 0 <= Z <= Y, you will need to calculate the percentage of Z of (Y - X), since Z will be the top position.

    So, instead of calculating the percentage value of your scroll position compared to document size, you will need to calculate its percentage compared to the difference between the document size and the screen size.