From 953bb679406e049a19665a1df37ca7c05730c409 Mon Sep 17 00:00:00 2001 From: monoid Date: Sat, 13 Apr 2024 12:40:20 +0900 Subject: [PATCH] inifinite scroll implement --- packages/client/package.json | 1 + packages/client/src/hook/useSearchGallery.ts | 2 + packages/client/src/page/galleryPage.tsx | 82 ++++++++++++++++---- pnpm-lock.yaml | 18 +++++ 4 files changed, 88 insertions(+), 15 deletions(-) diff --git a/packages/client/package.json b/packages/client/package.json index 0fdddb9..4841070 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -17,6 +17,7 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tooltip": "^1.0.7", + "@tanstack/react-virtual": "^3.2.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "dbtype": "workspace:*", diff --git a/packages/client/src/hook/useSearchGallery.ts b/packages/client/src/hook/useSearchGallery.ts index 9962ded..043c5e8 100644 --- a/packages/client/src/hook/useSearchGallery.ts +++ b/packages/client/src/hook/useSearchGallery.ts @@ -30,6 +30,7 @@ export function useSearchGalleryInfinite(searchParams: SearchParams = {}) { { data: Document[]; nextCursor: number | null; + startCursor: number | null; hasMore: boolean; } >((index, previous) => { @@ -48,6 +49,7 @@ export function useSearchGalleryInfinite(searchParams: SearchParams = {}) { const res = await fetcher(url); return { data: res, + startCursor: res.length === 0 ? null : res[0].id, nextCursor: res.length === 0 ? null : res[res.length - 1].id, hasMore: limit ? res.length === limit : (res.length === 20), }; diff --git a/packages/client/src/page/galleryPage.tsx b/packages/client/src/page/galleryPage.tsx index a318147..326dd00 100644 --- a/packages/client/src/page/galleryPage.tsx +++ b/packages/client/src/page/galleryPage.tsx @@ -5,7 +5,9 @@ import TagBadge from "@/components/gallery/TagBadge.tsx"; import { useSearchGalleryInfinite } from "../hook/useSearchGallery.ts"; import { Spinner } from "../components/Spinner.tsx"; import TagInput from "@/components/gallery/TagInput.tsx"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; +import { Separator } from "@/components/ui/separator.tsx"; +import { useVirtualizer } from "@tanstack/react-virtual"; export default function Gallery() { const search = useSearch(); @@ -19,21 +21,50 @@ export default function Gallery() { limit: limit ? Number.parseInt(limit) : undefined, cursor: cursor ? Number.parseInt(cursor) : undefined }); + const parentRef = useRef(null); + const virtualizer = useVirtualizer({ + count: size, + // biome-ignore lint/style/noNonNullAssertion: + getScrollElement: () => parentRef.current!, + estimateSize: (index) => { + const docs = data?.[index]; + if (!docs) return 8; + return docs.data.length * (200 + 8) + 37 + 8; + }, + overscan: 1, + }); + const virtualItems = virtualizer.getVirtualItems(); + useEffect(() => { + const lastItems = virtualItems.slice(-1); + // console.log(virtualItems); + if (lastItems.some(x => x.index >= size - 1)) { + const last = lastItems[0]; + const docs = data?.[last.index]; + if (docs?.hasMore) { + setSize(size + 1); + } + } + }, [virtualItems, setSize, size, data]); + if (isLoading) { return
Loading...
} if (error) { return
Error: {String(error)}
} + if (!data) { + return
No data
+ } + const isLoadingMore = data && size > 0 && (data[size - 1] === undefined); const isReachingEnd = data && data[size - 1]?.hasMore === false; - return (
+ return (
{(word || tags) && -
+
{word && Search: {word}} {tags && Tags:
    {tags.split(",").map(x => )}
}
@@ -41,21 +72,42 @@ export default function Gallery() { { data?.length === 0 &&
No results
} +
{ // TODO: date based grouping - data?.map((docs) => { - return docs?.data?.map((x) => { - return ( - - ); - }); + virtualItems.map((item) => { + const isLoaderRow = item.index === size - 1 && isLoadingMore; + if (isLoaderRow) { + return
+ +
; + } + const docs = data[item.index]; + if (!docs) return null; + return
+ {docs.startCursor &&
+

Start with {docs.startCursor}

+ +
} + {docs?.data?.map((x) => { + return ( + + ); + })} +
}) } - { - - } +
); } @@ -70,7 +122,7 @@ function Search() { -