Is it true that when scrolling to the end offsetHeight + scrollTop == scrollHeight?

Viewed 28

I am making an infinite scroll component in react. I check (offsetHeight + scrollTop == scrollHeight) to realize scrolled to the end. However, when scrolling to the end sometimes offsetHeight + scrollTop is not equal to scrollHeight.

  const handleScroll = async (e) => {
    const { offsetHeight, scrollTop, scrollHeight } = e.target;
    console.log(offsetHeight + scrollTop + " ==  " + scrollHeight);
    if (offsetHeight + scrollTop == scrollHeight) {
      console.log("ok");
      setStep((prev) => prev + step);
      fetchData(nowStep + step);
    }
  };

  return (
    <div
      onScroll={handleScroll}
      style={{
        height: height,
        overflowY: "scroll",
        overflowX: "hidden",
        width: "100%",
        padding: 0,
        margin: 0,
        textAlign: "center",
      }}
    >
      {children}
    </div>

Here's what I think:

enter image description here

Edit: I realized the browser zoom could be the cause. At some zoom levels eg: 125%, 100%, 75%, 67% the code runs fine, but at 110%, 90%, 80%, the check results are not as expected. Console when scrolling to the end:

  • 110% zoom browser:
690.9090881347656 ==  696
694.5454406738281 ==  696
695.757568359375 ==  696
  • 100% zoom browser:
694.6666564941406 ==  696
695.3333435058594 ==  696
696 ==  696
ok
  • 90% zoom browser:
694.0740966796875 ==  696
694.8148498535156 ==  696
695.5555725097656 ==  696
1 Answers

Don't overcomplicate things. You can achieve an endless scrolling much easier with Intersection Observer (IO)

With IO you can observe an element and react whenever it intersects with either the viewport or another element. For your case you want it to trigger a function whenever it comes into view (intersects with the viewport)

You create a dummy-div at the bottom of your Page and create an IO. Then you just wait for it to come into view and do your logic for adding more items:

let observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      addAnotherRow();
    }
  })

});

const target = document.querySelector('#dummy');

observer.observe(target);

addAnotherRow = () => {
  const template = document.querySelector('#moreItem');
  const clone = template.content.cloneNode(true);

  document.querySelector('ul').appendChild(clone);
}
ul {
  min-height: 110vh;
}

li {
  min-height: 47vh;
}
<ul>
  <li> Test </li>
  <li> Item </li>
  <li> More Content </li>
</ul>

<div id="dummy"> </div>

<template id="moreItem">
<li> Lazy Loaded items </li>
</template>

Related