diff --git a/package.json b/package.json index e3c630e..6b8e8b8 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "@react-sandbox/heart": "^1.1.0", "@sentry/nextjs": "^8", "@sentry/react": "^8.26.0", + "@tanstack/react-query": "^5.60.2", + "@tanstack/react-query-devtools": "^5.60.2", "@types/react-query": "^1.2.9", "antd": "^5.20.0", "basic-loading": "^2.0.2", diff --git a/src/app/(pages)/4q-gallery/_components/item-container.tsx b/src/app/(pages)/4q-gallery/_components/item-container.tsx index 8d03203..4883879 100644 --- a/src/app/(pages)/4q-gallery/_components/item-container.tsx +++ b/src/app/(pages)/4q-gallery/_components/item-container.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useInfiniteQuery } from "@tanstack/react-query"; import styles from "./item-container.module.css"; import ItemCard from "./item-card"; import { getGalleryData } from "@/service/photo_api"; @@ -13,7 +13,16 @@ type Item = { categoryName: string; url: string; tags: string[]; - liked: boolean; + liked: boolean; +}; + +type GalleryPage = { + content: Item[]; + page: number; + number: number; + last: boolean; + totalPages: number; + totalElements: number; }; type ContainerProps = { @@ -27,57 +36,53 @@ export default function Container({ category, tag, sort }: ContainerProps) { size: 12, color: "#FE5B10", }; - - const [items, setItems] = useState([]); - const [loading, setLoading] = useState(true); - const [hasMore, setHasMore] = useState(true); - const [page, setPage] = useState(0); - - useEffect(() => { - const fetchData = async () => { - setLoading(true); - try { - const data = await getGalleryData(page, category, tag, sort); - setItems((prevItems) => - page === 0 ? data.content : [...prevItems, ...data.content] - ); - setHasMore(!data.last); - } catch (error) { - console.error("Error fetching gallery data:", error); - } finally { - setLoading(false); + const { + data, + isLoading, + isError, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + } = useInfiniteQuery({ + queryKey: ["galleryData", category, tag, sort], + queryFn: ({ pageParam = 0 }) => + getGalleryData({ pageParam, category, tag, sort }), + initialPageParam: 0, + getNextPageParam: (lastPage) => { + if (lastPage && !lastPage.last) { + console.log(lastPage); + return lastPage.number + 1; } - }; - - fetchData(); - }, [page, category, tag, sort]); + return undefined; + }, + staleTime: 60 * 1000, + gcTime: 300 * 1000, + }); - useEffect(() => { - setPage(0); - }, [category, tag, sort]); - - if (loading && items.length === 0) { + if (isLoading) { return ( -
+
); } - const loadMore = () => { - setPage((prevPage) => prevPage + 1); - }; + if (isError) { + return
Error loading gallery data.
; + } + + const items = data?.pages.flatMap((page) => page.content) || []; return (
- {items.map((item) => ( + {items.map((item: Item) => ( ))} - {hasMore && ( + {hasNextPage && (