What's new
IntersectionObserver-based triggering
next() is now fired by an IntersectionObserver watching an invisible sentinel div at the end of the list, instead of a throttled scroll event listener. IO runs off the main thread and requires no throttling, scripting overhead drops from ~29% to ~23%.
Zero runtime dependencies
throttle-debounce has been removed. The package now ships with no runtime dependencies.
Function component rewrite
The class component has been fully replaced with a function component using useRef/useEffect/useState. The public API is unchanged.
Bug fixes
- Inverse scroll: sentinel is now always the last DOM child. In a
flex-direction: column-reversecontainer this places it at the visual top, sonext()fires at the correct threshold as the user scrolls up rather than requiring a full scroll to the opposite end. onScrollprop type: corrected fromMouseEventtoUIEvent.scrollableTargetprop type: corrected fromReactNodetoHTMLElement | string | null.
Build tooling
- Rollup 1 → 4
- TypeScript 4 → 5
- Rollup plugins migrated to
@rollup/*scoped packages
Notes
scrollThreshold: semantics are unchanged (0.8= 80% threshold,"200px"= fixed pixel pre-trigger). Internally this now maps to IOrootMarginrather than a scroll position calculation.- Inline function props: passing
nextorrefreshFunctionas inline arrow functions no longer causes the observer to reconnect on every render. Stable callback refs are used internally. - Graceful degradation: if
IntersectionObserveris unavailable, the component renders silently without triggeringnext(). No error is thrown. - SSR / Next.js: safe to render server-side. The IO guard (
typeof IntersectionObserver === 'undefined') prevents any server-side attachment. - React 18 StrictMode: double effect invocation is handled correctly. The observer is disconnected on cleanup and will not fire duplicate
next()calls.
Upgrading
No prop changes. Drop-in replacement for v7.0.0.