changed feed page to paginate requests
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
|||||||
QueryClient,
|
QueryClient,
|
||||||
QueryClientProvider,
|
QueryClientProvider,
|
||||||
useQuery,
|
useQuery,
|
||||||
|
useInfiniteQuery,
|
||||||
useMutation,
|
useMutation,
|
||||||
useQueryClient,
|
useQueryClient,
|
||||||
} from "@tanstack/react-query";
|
} from "@tanstack/react-query";
|
||||||
@@ -861,21 +862,54 @@ function TweetDetail({ tweetId }: { tweetId: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FEED_PAGE_SIZE = 10;
|
||||||
|
|
||||||
function Feed() {
|
function Feed() {
|
||||||
const { data, isLoading, isError, error, refetch } = useQuery({
|
const sentinelRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
fetchNextPage,
|
||||||
|
hasNextPage,
|
||||||
|
isFetchingNextPage,
|
||||||
|
} = useInfiniteQuery({
|
||||||
queryKey: ["tweets"],
|
queryKey: ["tweets"],
|
||||||
queryFn: async () => {
|
queryFn: async ({ pageParam }: { pageParam: number }) => {
|
||||||
const res = await readTweet({
|
const res = await readTweet({
|
||||||
fields: ["id", "content", "likes", "likedByMe", "userId", "state", "userEmail", "insertedAt", { media: ["id", "s3Key"] }],
|
fields: ["id", "content", "likes", "likedByMe", "userId", "state", "userEmail", "insertedAt", { media: ["id", "s3Key"] }],
|
||||||
sort: "-insertedAt",
|
sort: "-insertedAt",
|
||||||
|
page: { limit: FEED_PAGE_SIZE, offset: pageParam },
|
||||||
headers: buildCSRFHeaders(),
|
headers: buildCSRFHeaders(),
|
||||||
});
|
});
|
||||||
if (!res.success) throw new Error("Failed to load tweets");
|
if (!res.success) throw new Error("Failed to load tweets");
|
||||||
const tweets = Array.isArray(res.data) ? res.data : (res.data as any)?.results ?? [];
|
const pageData = res.data as any;
|
||||||
return tweets as Tweet[];
|
const tweets: Tweet[] = Array.isArray(pageData) ? pageData : (pageData?.results ?? []);
|
||||||
|
const hasMore: boolean = Array.isArray(pageData) ? false : (pageData?.hasMore ?? false);
|
||||||
|
return { tweets, hasMore, nextOffset: pageParam + FEED_PAGE_SIZE };
|
||||||
},
|
},
|
||||||
|
initialPageParam: 0,
|
||||||
|
getNextPageParam: (lastPage) => lastPage.hasMore ? lastPage.nextOffset : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// IntersectionObserver — fires fetchNextPage when the sentinel div scrolls into view
|
||||||
|
useEffect(() => {
|
||||||
|
const el = sentinelRef.current;
|
||||||
|
if (!el) return;
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
if (entries[0].isIntersecting && hasNextPage && !isFetchingNextPage) {
|
||||||
|
fetchNextPage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ threshold: 0.1 },
|
||||||
|
);
|
||||||
|
observer.observe(el);
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
|
||||||
|
|
||||||
if (isLoading) return <Spinner />;
|
if (isLoading) return <Spinner />;
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return (
|
return (
|
||||||
@@ -883,7 +917,7 @@ function Feed() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tweets = data ?? [];
|
const tweets = data?.pages.flatMap((p) => p.tweets) ?? [];
|
||||||
|
|
||||||
if (tweets.length === 0) {
|
if (tweets.length === 0) {
|
||||||
return (
|
return (
|
||||||
@@ -900,6 +934,9 @@ function Feed() {
|
|||||||
{tweets.map((t) => (
|
{tweets.map((t) => (
|
||||||
<TweetCard key={t.id} tweet={t} />
|
<TweetCard key={t.id} tweet={t} />
|
||||||
))}
|
))}
|
||||||
|
{/* Sentinel element — entering the viewport triggers loading the next page */}
|
||||||
|
<div ref={sentinelRef} style={{ height: "1px" }} />
|
||||||
|
{isFetchingNextPage && <Spinner />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user