Jelajahi Sumber

refactor RecentChanges

Yuki Takei 2 tahun lalu
induk
melakukan
40104987dc

+ 28 - 0
apps/app/src/components/Sidebar/RecentChanges/RecentChanges.tsx

@@ -0,0 +1,28 @@
+import { Suspense, useState } from 'react';
+
+import { useTranslation } from 'react-i18next';
+
+import RecentChangesContentSkeleton from './RecentChangesContentSkeleton';
+import { RecentChangesHeader, RecentChangesContent } from './RecentChangesSubstance';
+
+
+export const RecentChanges = (): JSX.Element => {
+  const { t } = useTranslation();
+
+  const [isSmall, setIsSmall] = useState(false);
+
+  return (
+    <div className="px-3" data-testid="grw-recent-changes">
+      <div className="grw-sidebar-content-header py-3 d-flex">
+        <h3 className="mb-0 text-nowrap">{t('Recent Changes')}</h3>
+        <Suspense>
+          <RecentChangesHeader isSmall={isSmall} onSizeChange={setIsSmall} />
+        </Suspense>
+      </div>
+
+      <Suspense fallback={<RecentChangesContentSkeleton />}>
+        <RecentChangesContent isSmall={isSmall} />
+      </Suspense>
+    </div>
+  );
+};

+ 1 - 1
apps/app/src/components/Sidebar/RecentChanges/RecentChangesContentSkeleton.tsx

@@ -2,7 +2,7 @@ import React from 'react';
 
 import { Skeleton } from '~/components/Skeleton';
 
-import styles from './RecentChanges.module.scss';
+import styles from './RecentChangesSubstance.module.scss';
 
 const SkeletonItem = () => {
 

+ 54 - 52
apps/app/src/components/Sidebar/RecentChanges/RecentChangesSubstance.tsx

@@ -17,9 +17,7 @@ import loggerFactory from '~/utils/logger';
 
 import { SidebarHeaderReloadButton } from '../SidebarHeaderReloadButton';
 
-import RecentChangesContentSkeleton from './RecentChangesContentSkeleton';
-
-import styles from './RecentChanges.module.scss';
+import styles from './RecentChangesSubstance.module.scss';
 
 
 const logger = loggerFactory('growi:History');
@@ -102,29 +100,27 @@ const PageItem = memo(({ page, isSmall }: PageItemProps): JSX.Element => {
 });
 PageItem.displayName = 'PageItem';
 
-export const RecentChanges = (): JSX.Element => {
 
-  const PER_PAGE = 20;
-  const { t } = useTranslation();
-  const swrInifinitexRecentlyUpdated = useSWRINFxRecentlyUpdated(PER_PAGE);
-  const {
-    data, mutate, isLoading,
-  } = swrInifinitexRecentlyUpdated;
+type HeaderProps = {
+  isSmall: boolean,
+  onSizeChange: (isSmall: boolean) => void,
+}
 
-  const [isRecentChangesSidebarSmall, setIsRecentChangesSidebarSmall] = useState(false);
-  const isEmpty = data?.[0]?.pages.length === 0;
-  const isReachingEnd = isEmpty || (data != null && data[data.length - 1]?.pages.length < PER_PAGE);
+const PER_PAGE = 20;
+export const RecentChangesHeader = ({ isSmall, onSizeChange }: HeaderProps): JSX.Element => {
+
+  const { mutate } = useSWRINFxRecentlyUpdated(PER_PAGE);
 
   const retrieveSizePreferenceFromLocalStorage = useCallback(() => {
     if (window.localStorage.isRecentChangesSidebarSmall === 'true') {
-      setIsRecentChangesSidebarSmall(true);
+      onSizeChange(true);
     }
-  }, []);
+  }, [onSizeChange]);
 
   const changeSizeHandler = useCallback((e) => {
-    setIsRecentChangesSidebarSmall(e.target.checked);
+    onSizeChange(e.target.checked);
     window.localStorage.setItem('isRecentChangesSidebarSmall', e.target.checked);
-  }, []);
+  }, [onSizeChange]);
 
   // componentDidMount
   useEffect(() => {
@@ -132,43 +128,49 @@ export const RecentChanges = (): JSX.Element => {
   }, [retrieveSizePreferenceFromLocalStorage]);
 
   return (
-    <div className="px-3" data-testid="grw-recent-changes">
-      <div className="grw-sidebar-content-header py-3 d-flex">
-        <h3 className="mb-0 text-nowrap">{t('Recent Changes')}</h3>
-        <SidebarHeaderReloadButton onClick={() => mutate()}/>
-        <div className="d-flex align-items-center">
-          <div className={`grw-recent-changes-resize-button ${styles['grw-recent-changes-resize-button']} custom-control custom-switch ml-1`}>
-            <input
-              id="recentChangesResize"
-              className="custom-control-input"
-              type="checkbox"
-              checked={isRecentChangesSidebarSmall}
-              onChange={changeSizeHandler}
-            />
-            <label className="custom-control-label" htmlFor="recentChangesResize">
-            </label>
-          </div>
+    <>
+      <SidebarHeaderReloadButton onClick={() => mutate()}/>
+      <div className="d-flex align-items-center">
+        <div className={`grw-recent-changes-resize-button ${styles['grw-recent-changes-resize-button']} custom-control custom-switch ml-1`}>
+          <input
+            id="recentChangesResize"
+            className="custom-control-input"
+            type="checkbox"
+            checked={isSmall}
+            onChange={changeSizeHandler}
+          />
+          <label className="custom-control-label" htmlFor="recentChangesResize" />
         </div>
       </div>
-      {
-        isLoading ? <RecentChangesContentSkeleton /> : (
-          <div className="grw-recent-changes py-3">
-            <ul className="list-group list-group-flush">
-              <InfiniteScroll
-                swrInifiniteResponse={swrInifinitexRecentlyUpdated}
-                isReachingEnd={isReachingEnd}
-              >
-                { data != null && data.map(apiResult => apiResult.pages).flat()
-                  .map(page => (
-                    <PageItem key={page._id} page={page} isSmall={isRecentChangesSidebarSmall} />
-                  ))
-                }
-              </InfiniteScroll>
-            </ul>
-          </div>
-        )
-      }
-    </div>
+    </>
   );
+};
+
+type ContentProps = {
+  isSmall: boolean,
+}
+
+export const RecentChangesContent = ({ isSmall }: ContentProps): JSX.Element => {
+  const swrInifinitexRecentlyUpdated = useSWRINFxRecentlyUpdated(PER_PAGE);
+  const { data } = swrInifinitexRecentlyUpdated;
 
+  const isEmpty = data?.[0]?.pages.length === 0;
+  const isReachingEnd = isEmpty || (data != null && data[data.length - 1]?.pages.length < PER_PAGE);
+
+  return (
+    <div className="grw-recent-changes py-3">
+      <ul className="list-group list-group-flush">
+        <InfiniteScroll
+          swrInifiniteResponse={swrInifinitexRecentlyUpdated}
+          isReachingEnd={isReachingEnd}
+        >
+          { data != null && data.map(apiResult => apiResult.pages).flat()
+            .map(page => (
+              <PageItem key={page._id} page={page} isSmall={isSmall} />
+            ))
+          }
+        </InfiniteScroll>
+      </ul>
+    </div>
+  );
 };