Infinite Scroll
Infinite scroll or lazy loading for lists data, modern alternative of pagination.
Installation
Usage
function CardSkelton() {
return (
<div className="flex flex-col space-y-6">
<div className="flex items-center gap-2">
<Skeleton className="size-8 rounded-full" />
<Skeleton className="w-full h-6 rounded" />
</div>
<Skeleton className="w-full h-24 rounded" />
</div>
);
}
export function InfiniteScrollDemo() {
const BASE_URL = 'https://jsonplaceholder.typicode.com/posts';
const LIMIT = 6;
const [posts, setPosts] = useState<Post[]>([]);
const [page, setPage] = useState<number>(0);
const [totalCount, setTotalCount] = useState<number | null>();
const [isPending, setIsPending] = useState<boolean>(false);
const fetchData = useCallback(async () => {
if (isPending) return;
setIsPending(true);
const start = page * LIMIT;
try {
const response = await fetch(
`${BASE_URL}?_start=${start}&_limit=${LIMIT}`,
);
const totalItems = response.headers.get('x-total-count');
const data = await response.json();
setTotalCount(Number(totalItems));
setPosts((prevPosts) => [...prevPosts, ...data]);
setPage((prevPage) => prevPage + 1);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setIsPending(false);
}
}, [page, isPending]);
useEffect(() => {
fetchData();
}, []);
return (
<InfiniteScroll
isPending={isPending}
currentItemsLength={posts.length}
allItemsCount={totalCount}
loadMore={fetchData}
className="grid grid-cols-[repeat(auto-fill,minmax(250px,1fr))] justify-center items-start gap-4 p-8"
>
{posts.map((post) => (
<InfiniteScrollCell
className="p-6 bg-card border border-border/50 rounded-xl shadow-2xs"
key={post.id}
amount={0.5}
skelton={<CardSkelton />}
>
<div className="flex flex-col space-y-6 ">
<div className="flex items-center gap-2">
<div className="font-semibold text-sm text-muted-foreground">
#{post.id}
</div>
<h2
title={post.title}
className="font-medium max-w-[15ch] capitalize line-clamp-1"
>
{post.title}
</h2>
</div>
<p className="text-sm text-muted-foreground">{post.body}</p>
</div>
</InfiniteScrollCell>
))}
</InfiniteScroll>
);
}Props
InfiniteScrollCell
| Prop | Type | Default |
|---|---|---|
amount? | UseInViewOptions['amount'] | - |
skelton? | ReactNode | - |
InfiniteScroll
| Prop | Type | Default |
|---|---|---|
loadMore | () => void | - |
allItemsCount | number | - |
isPending | boolean | - |
currentItemsLength | number | - |