feat: add infinite scroll to community page

Replace the manual "Load More" button with IntersectionObserver-based
infinite scroll using a sentinel div with 200px root margin for
pre-fetching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sahaj Jain
2026-02-11 03:28:09 +05:30
parent d77cf471a4
commit 815b1fac19
@@ -3,6 +3,7 @@
import { useCommunityThemes } from "@/hooks/themes";
import type { CommunitySortOption } from "@/types/community";
import { useQueryState, parseAsStringLiteral } from "nuqs";
import { useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
@@ -37,6 +38,25 @@ export function CommunityThemesContent() {
const themes = data?.pages.flatMap((page) => page.themes) ?? [];
const sentinelRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const sentinel = sentinelRef.current;
if (!sentinel) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
},
{ rootMargin: "200px" }
);
observer.observe(sentinel);
return () => observer.disconnect();
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
return (
<div className="space-y-6">
<div className="flex items-center justify-between gap-4">
@@ -134,25 +154,11 @@ export function CommunityThemesContent() {
))}
</div>
{hasNextPage && (
<div className="flex justify-center pt-4">
<Button
variant="outline"
size="lg"
onClick={() => fetchNextPage()}
disabled={isFetchingNextPage}
>
{isFetchingNextPage ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Loading...
</>
) : (
"Load More"
)}
</Button>
</div>
)}
<div ref={sentinelRef} className="flex justify-center pt-4">
{isFetchingNextPage && (
<Loader2 className="text-muted-foreground h-6 w-6 animate-spin" />
)}
</div>
</>
)}
</div>