You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I updated to v7 with useInfiniteScroll exactly like in the basic example. Unlike in previous version, now if I hold End, at some point it stops loading. If I scroll up and then down again it loads again.
Probably in addition to IntersectionObserver, you also need to make sure if it's not already visible at the time it's added to the DOM.
// IntersectionObserver fires only when the sentinel transitions across// threshold 0; holding End keeps it continuously inside the trigger zone so// the hook stops firing. A scroll listener catches each browser-applied// scroll (one per End keypress) and chains the next batch.consttotalCount=myData.length;useEffect(()=>{constroot=document.getElementById('MyContentWrapper');// scrollableTargetif(!root){return;}consthandleScroll=()=>{if(root.scrollHeight-(root.scrollTop+root.clientHeight)>root.clientHeight){return;}setInfiniteScrollLoadedItems((prev)=>prev<totalCount ? Math.min(prev+30,totalCount) : prev);};root.addEventListener('scroll',handleScroll,{passive: true});return()=>root.removeEventListener('scroll',handleScroll);},[totalCount]);
Thanks for the detailed report and the correct intuition on the root cause!
This is a confirmed bug. The IntersectionObserver only fires on intersection changes, not the current state. When new data loads while the sentinel is already visible, Effect 2a resets the load guard but the IO never re-fires, leaving the component stuck until the user scrolls away and back. Your workaround (scroll up, then down) triggers a fresh intersection event, which is why it works.
The fix is straightforward: after resetting the guard on new data, force the IO to re-evaluate by calling observer.unobserve(sentinel) + observer.observe(sentinel) on the existing observer instance. No API changes needed, this would be a patch release.
If you're interested in contributing a fix, we'd love that and are happy to review a PR. The relevant code is in src/index.tsx, specifically Effect 2a (dataLength dep) and Effect 2b (the IO lifecycle). Happy to give more detail on the approach if it helps.
Activity
justanotheranonymoususer commentedon May 2, 2026
Adding this as a workaround worked for me:
iamdarshshah commentedon May 2, 2026
Thanks for the detailed report and the correct intuition on the root cause!
This is a confirmed bug. The
IntersectionObserveronly fires on intersection changes, not the current state. When new data loads while the sentinel is already visible, Effect 2a resets the load guard but the IO never re-fires, leaving the component stuck until the user scrolls away and back. Your workaround (scroll up, then down) triggers a fresh intersection event, which is why it works.The fix is straightforward: after resetting the guard on new data, force the IO to re-evaluate by calling
observer.unobserve(sentinel)+observer.observe(sentinel)on the existing observer instance. No API changes needed, this would be a patch release.If you're interested in contributing a fix, we'd love that and are happy to review a PR. The relevant code is in
src/index.tsx, specifically Effect 2a (dataLengthdep) and Effect 2b (the IO lifecycle). Happy to give more detail on the approach if it helps.fix: re-observe sentinel on data load so IO re-fires when still in tr…
test: add regression tests for sentinel re-observe on dataLength change
justanotheranonymoususer commentedon May 2, 2026
#430