Bläddra i källkod

refactor modal components for performance

Yuki Takei 8 månader sedan
förälder
incheckning
65b68d47c8

+ 19 - 20
apps/app/src/client/components/DeleteBookmarkFolderModal.tsx

@@ -1,6 +1,6 @@
 
 import type { FC } from 'react';
-import React from 'react';
+import { useCallback } from 'react';
 
 import { useTranslation } from 'next-i18next';
 import {
@@ -15,31 +15,30 @@ import { useDeleteBookmarkFolderModalStatus, useDeleteBookmarkFolderModalActions
 
 const DeleteBookmarkFolderModal: FC = () => {
   const { t } = useTranslation();
-  const deleteBookmarkFolderModalData = useDeleteBookmarkFolderModalStatus();
+
+  const { isOpened, bookmarkFolder, opts } = useDeleteBookmarkFolderModalStatus();
   const { close: closeBookmarkFolderDeleteModal } = useDeleteBookmarkFolderModalActions();
-  const isOpened = deleteBookmarkFolderModalData?.isOpened ?? false;
 
-  async function deleteBookmark() {
-    if (deleteBookmarkFolderModalData == null || deleteBookmarkFolderModalData.bookmarkFolder == null) {
+  const deleteBookmark = useCallback(async() => {
+    if (bookmarkFolder == null) {
       return;
     }
-    if (deleteBookmarkFolderModalData.bookmarkFolder != null) {
-      try {
-        await deleteBookmarkFolder(deleteBookmarkFolderModalData.bookmarkFolder._id);
-        const onDeleted = deleteBookmarkFolderModalData.opts?.onDeleted;
-        if (onDeleted != null) {
-          onDeleted(deleteBookmarkFolderModalData.bookmarkFolder._id);
-        }
-        closeBookmarkFolderDeleteModal();
-      }
-      catch (err) {
-        toastError(err);
+    try {
+      await deleteBookmarkFolder(bookmarkFolder._id);
+      const onDeleted = opts?.onDeleted;
+      if (onDeleted != null) {
+        onDeleted(bookmarkFolder._id);
       }
+      closeBookmarkFolderDeleteModal();
     }
-  }
-  async function onClickDeleteButton() {
+    catch (err) {
+      toastError(err);
+    }
+  }, [bookmarkFolder, closeBookmarkFolderDeleteModal, opts?.onDeleted]);
+
+  const onClickDeleteButton = useCallback(async() => {
     await deleteBookmark();
-  }
+  }, [deleteBookmark]);
 
   return (
     <Modal size="md" isOpen={isOpened} toggle={closeBookmarkFolderDeleteModal} data-testid="page-delete-modal" className="grw-create-page">
@@ -50,7 +49,7 @@ const DeleteBookmarkFolderModal: FC = () => {
       <ModalBody>
         <div className="pb-1 text-break">
           <label className="form-label">{ t('bookmark_folder.delete_modal.modal_body_description') }:</label><br />
-          <FolderIcon isOpen={false} /> {deleteBookmarkFolderModalData?.bookmarkFolder?.name}
+          <FolderIcon isOpen={false} /> {bookmarkFolder?.name}
         </div>
         {t('bookmark_folder.delete_modal.modal_body_alert')}
       </ModalBody>

+ 11 - 17
apps/app/src/client/components/EmptyTrashModal.tsx

@@ -1,7 +1,5 @@
 import type { FC } from 'react';
-import React, {
-  useState,
-} from 'react';
+import React, { useState, useCallback } from 'react';
 
 import { useTranslation } from 'next-i18next';
 import {
@@ -16,23 +14,21 @@ import ApiErrorMessageList from './PageManagement/ApiErrorMessageList';
 const EmptyTrashModal: FC = () => {
   const { t } = useTranslation();
 
-  const emptyTrashModalData = useEmptyTrashModalStatus();
+  const { isOpened, pages, opts } = useEmptyTrashModalStatus();
   const { close: closeEmptyTrashModal } = useEmptyTrashModalActions();
 
-  const isOpened = emptyTrashModalData?.isOpened ?? false;
-
-  const canDeleteAllpages = emptyTrashModalData?.opts?.canDeleteAllPages ?? false;
+  const canDeleteAllpages = opts?.canDeleteAllPages ?? false;
 
   const [errs, setErrs] = useState<Error[] | null>(null);
 
-  async function emptyTrash() {
-    if (emptyTrashModalData == null || emptyTrashModalData.pages == null) {
+  const emptyTrash = useCallback(async() => {
+    if (pages == null) {
       return;
     }
 
     try {
       await apiv3Delete('/pages/empty-trash');
-      const onEmptiedTrash = emptyTrashModalData.opts?.onEmptiedTrash;
+      const onEmptiedTrash = opts?.onEmptiedTrash;
       if (onEmptiedTrash != null) {
         onEmptiedTrash();
       }
@@ -41,15 +37,13 @@ const EmptyTrashModal: FC = () => {
     catch (err) {
       setErrs([err]);
     }
-  }
+  }, [pages, opts?.onEmptiedTrash, closeEmptyTrashModal]);
 
-  async function emptyTrashButtonHandler() {
+  const emptyTrashButtonHandler = useCallback(async() => {
     await emptyTrash();
-  }
-
-  const renderPagePaths = () => {
-    const pages = emptyTrashModalData?.pages;
+  }, [emptyTrash]);
 
+  const renderPagePaths = useCallback(() => {
     if (pages != null) {
       return pages.map(page => (
         <p key={page.data._id} className="mb-1">
@@ -58,7 +52,7 @@ const EmptyTrashModal: FC = () => {
       ));
     }
     return <></>;
-  };
+  }, [pages]);
 
   return (
     <Modal size="lg" isOpen={isOpened} toggle={closeEmptyTrashModal} data-testid="page-delete-modal">

+ 16 - 19
apps/app/src/client/components/PageDeleteModal.tsx

@@ -49,13 +49,10 @@ const isIPageInfoForEntityForDeleteModal = (pageInfo: any | undefined): pageInfo
 
 const PageDeleteModal: FC = () => {
   const { t } = useTranslation();
-
-  const deleteModalData = usePageDeleteModalStatus();
+  const { isOpened, pages, opts } = usePageDeleteModalStatus() ?? {};
   const { close: closeDeleteModal } = usePageDeleteModalActions();
 
-  const isOpened = deleteModalData?.isOpened ?? false;
-
-  const notOperatablePages: IPageToDeleteWithMeta[] = (deleteModalData?.pages ?? [])
+  const notOperatablePages: IPageToDeleteWithMeta[] = (pages ?? [])
     .filter(p => !isIPageInfoForEntityForDeleteModal(p.meta));
   const notOperatablePageIds = notOperatablePages.map(p => p.data._id);
 
@@ -63,8 +60,8 @@ const PageDeleteModal: FC = () => {
 
   // inject IPageInfo to operate
   let injectedPages: IDataWithMeta<HasObjectId & { path: string }, IPageInfoForEntity>[] | null = null;
-  if (deleteModalData?.pages != null) {
-    injectedPages = injectTo(deleteModalData?.pages);
+  if (pages != null) {
+    injectedPages = injectTo(pages);
   }
 
   // calculate conditions to delete
@@ -79,11 +76,11 @@ const PageDeleteModal: FC = () => {
 
   // calculate condition to determine modal status
   const forceDeleteCompletelyMode = useMemo(() => {
-    if (deleteModalData != null && deleteModalData.pages != null && deleteModalData.pages.length > 0) {
-      return deleteModalData.pages.every(pageWithMeta => isTrashPage(pageWithMeta.data?.path ?? ''));
+    if (pages != null && pages.length > 0) {
+      return pages.every(pageWithMeta => isTrashPage(pageWithMeta.data?.path ?? ''));
     }
     return false;
-  }, [deleteModalData]);
+  }, [pages]);
 
   const [isDeleteRecursively, setIsDeleteRecursively] = useState(true);
   const [isDeleteCompletely, setIsDeleteCompletely] = useState(forceDeleteCompletelyMode);
@@ -116,7 +113,7 @@ const PageDeleteModal: FC = () => {
   }
 
   async function deletePage() {
-    if (deleteModalData == null || deleteModalData.pages == null) {
+    if (pages == null) {
       return;
     }
 
@@ -128,13 +125,13 @@ const PageDeleteModal: FC = () => {
     /*
      * When multiple pages
      */
-    if (deleteModalData.pages.length > 1) {
+    if (pages.length > 1) {
       try {
         const isRecursively = isDeleteRecursively === true ? true : undefined;
         const isCompletely = isDeleteCompletely === true ? true : undefined;
 
         const pageIdToRevisionIdMap = {};
-        deleteModalData.pages.forEach((p) => { pageIdToRevisionIdMap[p.data._id] = p.data.revision as string });
+        pages.forEach((p) => { pageIdToRevisionIdMap[p.data._id] = p.data.revision as string });
 
         const { data } = await apiv3Post<IDeleteManyPageApiv3Result>('/pages/delete', {
           pageIdToRevisionIdMap,
@@ -142,7 +139,7 @@ const PageDeleteModal: FC = () => {
           isCompletely,
         });
 
-        const onDeleted = deleteModalData.opts?.onDeleted;
+        const onDeleted = opts?.onDeleted;
         if (onDeleted != null) {
           onDeleted(data.paths, data.isRecursively, data.isCompletely);
         }
@@ -160,7 +157,7 @@ const PageDeleteModal: FC = () => {
         const recursively = isDeleteRecursively === true ? true : undefined;
         const completely = forceDeleteCompletelyMode || isDeleteCompletely ? true : undefined;
 
-        const page = deleteModalData.pages[0].data;
+        const page = pages[0].data;
 
         const { path, isRecursively, isCompletely } = await apiPost('/pages.remove', {
           page_id: page._id,
@@ -169,7 +166,7 @@ const PageDeleteModal: FC = () => {
           completely,
         }) as IDeleteSinglePageApiv1Result;
 
-        const onDeleted = deleteModalData.opts?.onDeleted;
+        const onDeleted = opts?.onDeleted;
         if (onDeleted != null) {
           onDeleted(path, isRecursively, isCompletely);
         }
@@ -232,10 +229,10 @@ const PageDeleteModal: FC = () => {
   }
 
   const renderPagePathsToDelete = () => {
-    const pages = injectedPages != null && injectedPages.length > 0 ? injectedPages : deleteModalData?.pages;
+    const renderingPages = injectedPages != null && injectedPages.length > 0 ? injectedPages : pages;
 
-    if (pages != null) {
-      return pages.map(page => (
+    if (renderingPages != null) {
+      return renderingPages.map(page => (
         <p key={page.data._id} className="mb-1">
           <code>{ page.data.path }</code>
           { page.meta?.isDeletable != null && !page.meta.isDeletable && <span className="ms-3 text-danger"><strong>(CAN NOT TO DELETE)</strong></span> }