Infinite Scroll
High-performance infinite scroll hook for React using the Intersection Observer API.
Installation
npm install @windowing-kit/infinite-scroll
# or
pnpm add @windowing-kit/infinite-scroll
# or
yarn add @windowing-kit/infinite-scroll
Quick Start
import { useInfiniteScroll } from "@windowing-kit/infinite-scroll";
import { useInfiniteState } from "./useInfiniteState";
function MyInfiniteList() {
const { items, hasNextPage, loading, fetchData } = useInfiniteState();
const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: fetchData,
rootMargin: "200px",
initialLoad: true,
});
return (
<div>
{items.map((item) => (
<div key={item.id}>{item.name}</div>
))}
<div ref={ref}>
{isFetching && <div>Loading...</div>}
{!hasNextPage && <div>No more items</div>}
</div>
</div>
);
}
API
useInfiniteScroll(options)
Infinite scroll hook.
Options
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
loading | boolean | Yes | - | Whether data is currently being loaded |
hasNextPage | boolean | Yes | - | Whether there is more data to load |
onLoadMore | () => void | Promise<void> | Yes | - | Callback function to load more data |
rootMargin | string | No | "0px" | Root margin for Intersection Observer |
disabled | boolean | No | false | Whether to disable infinite scroll |
delayInMs | number | No | 100 | Delay in milliseconds before triggering onLoadMore |
initialLoad | boolean | No | false | Whether to automatically load data on initial mount |
Return
| Property | Type | Description |
|---|---|---|
ref | VisibilityRefCallback | Ref callback to attach to the trigger element (usually the last item or sentinel) |
isFetching | boolean | Whether data is currently being fetched (same as loading) |
Examples
Basic Usage
function InfiniteList() {
const { items, hasNextPage, loading, fetchData } = useInfiniteState();
const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: fetchData,
});
return (
<div>
{items.map((item) => (
<Item key={item.id} item={item} />
))}
<div ref={ref}>{isFetching && <Spinner />}</div>
</div>
);
}
With Custom Root Margin
const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: loadMore,
rootMargin: "300px", // Start loading 300px before reaching the bottom
});
Disable on Condition
const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: loadMore,
disabled: !user.isAuthenticated, // Disable if user is not authenticated
});
Initial Load
const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: loadMore,
initialLoad: true, // Automatically load data when component mounts
});