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:
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:
690.9090881347656 == 696
694.5454406738281 == 696
695.757568359375 == 696
694.6666564941406 == 696
695.3333435058594 == 696
696 == 696
ok
694.0740966796875 == 696
694.8148498535156 == 696
695.5555725097656 == 696
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>