mirror of
https://github.com/mroxso/zelo-news.git
synced 2026-04-09 15:07:06 +02:00
1.7 KiB
1.7 KiB
Infinite Scroll for Nostr Feeds
For feed-like interfaces, implement infinite scroll using TanStack Query's useInfiniteQuery with Nostr's timestamp-based pagination:
import { useNostr } from '@nostrify/react';
import { useInfiniteQuery } from '@tanstack/react-query';
export function useGlobalFeed() {
const { nostr } = useNostr();
return useInfiniteQuery({
queryKey: ['global-feed'],
queryFn: async ({ pageParam, signal }) => {
const filter = { kinds: [1], limit: 20 };
if (pageParam) filter.until = pageParam;
const events = await nostr.query([filter], {
signal: AbortSignal.any([signal, AbortSignal.timeout(1500)])
});
return events;
},
getNextPageParam: (lastPage) => {
if (lastPage.length === 0) return undefined;
return lastPage[lastPage.length - 1].created_at - 1; // Subtract 1 since 'until' is inclusive
},
initialPageParam: undefined,
});
}
Example usage with intersection observer for automatic loading:
import { useInView } from 'react-intersection-observer';
function GlobalFeed() {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useGlobalFeed();
const { ref, inView } = useInView();
useEffect(() => {
if (inView && hasNextPage) {
fetchNextPage();
}
}, [inView, hasNextPage, fetchNextPage]);
const posts = data?.pages.flat() || [];
return (
<div className="space-y-4">
{posts.map((post) => (
<PostCard key={post.id} post={post} />
))}
{hasNextPage && (
<div ref={ref} className="py-4">
{isFetchingNextPage && <Skeleton className="h-20 w-full" />}
</div>
)}
</div>
);
}