Просмотр исходного кода

implement infinite-scroll into PageTimeline

reiji-h 2 лет назад
Родитель
Сommit
2cda6757e9
1 измененных файлов с 39 добавлено и 26 удалено
  1. 39 26
      apps/app/src/components/PageTimeline.tsx

+ 39 - 26
apps/app/src/components/PageTimeline.tsx

@@ -2,12 +2,14 @@ import React, { useCallback, useEffect, useState } from 'react';
 
 import { useTranslation } from 'next-i18next';
 import Link from 'next/link';
+import useSWRInfinite, { SWRInfiniteResponse } from 'swr/infinite';
 
 import { apiv3Get } from '~/client/util/apiv3-client';
 import { IPageHasId } from '~/interfaces/page';
 import { useCurrentPagePath } from '~/stores/page';
 import { useTimelineOptions } from '~/stores/renderer';
 
+import InfiniteScroll from './InfiniteScroll';
 import { RevisionLoader } from './Page/RevisionLoader';
 import PaginationWrapper from './PaginationWrapper';
 
@@ -42,30 +44,39 @@ const TimelineCard = ({ page }: TimelineCardProps): JSX.Element => {
   );
 };
 
+type PageTimelineResult = {
+  pages: IPageHasId[],
+  totalCount: number,
+  offset: number,
+}
+const useSWRINFxPageTimeline = (path: string, limit: number) : SWRInfiniteResponse<PageTimelineResult, Error> => {
+  return useSWRInfinite(
+    (pageIndex, previousPageData) => {
+      if (previousPageData != null && previousPageData.pages.length === 0) return null;
+
+      return ['/pages/list', path, pageIndex + 1, limit];
+    },
+    ([endpoint, path, page, limit]) => apiv3Get<PageTimelineResult>(endpoint, { path, page, limit }).then(response => response.data),
+    {
+      revalidateFirstPage: false,
+      revalidateAll: false,
+    },
+  );
+};
+
 
 export const PageTimeline = (): JSX.Element => {
-  const [activePage, setActivePage] = useState(1);
-  const [totalPageItems, setTotalPageItems] = useState(0);
-  const [limit, setLimit] = useState(10);
-  const [pages, setPages] = useState<IPageHasId[] | null>(null);
 
-  const { data: currentPagePath } = useCurrentPagePath();
+  const PER_PAGE = 5;
   const { t } = useTranslation();
+  const { data: currentPagePath } = useCurrentPagePath();
+  const swrInfinitexPageTimeline = useSWRINFxPageTimeline(currentPagePath, PER_PAGE);
+  const { data } = swrInfinitexPageTimeline;
 
-  const handlePage = useCallback(async(selectedPage: number) => {
-    if (currentPagePath == null) { return }
-    const res = await apiv3Get('/pages/list', { path: currentPagePath, page: selectedPage });
-    setTotalPageItems(res.data.totalCount);
-    setPages(res.data.pages);
-    setLimit(res.data.limit);
-    setActivePage(selectedPage);
-  }, [currentPagePath]);
-
-  useEffect(() => {
-    handlePage(1);
-  }, [handlePage]);
+  const isEmpty = data?.[0]?.pages.length === 0;
+  const isReachingEnd = isEmpty || (data != null && data[data.length - 1]?.pages.length < PER_PAGE);
 
-  if (pages == null || pages.length === 0) {
+  if (data == null || isEmpty) {
     return (
       <div className="mt-2">
         {/* eslint-disable-next-line react/no-danger */}
@@ -76,14 +87,16 @@ export const PageTimeline = (): JSX.Element => {
 
   return (
     <div>
-      { pages.map(page => <TimelineCard key={page._id} page={page} />) }
-      <PaginationWrapper
-        activePage={activePage}
-        changePage={handlePage}
-        totalItemsCount={totalPageItems}
-        pagingLimit={limit}
-        align="center"
-      />
+      <InfiniteScroll
+        swrInifiniteResponse={swrInfinitexPageTimeline}
+        isReachingEnd={isReachingEnd}
+      >
+        { data != null && data.map(apiResult => apiResult.pages).flat()
+          .map(page => (
+            <TimelineCard key={page._id} page={page} />
+          ))
+        }
+      </InfiniteScroll>
     </div>
   );
 };