Browse Source

WIP: migrate hooks for modal

Yuki Takei 7 months ago
parent
commit
73776131d1

+ 3 - 2
apps/app/src/client/components/EmptyTrashModal.tsx

@@ -9,14 +9,15 @@ import {
 } from 'reactstrap';
 
 import { apiv3Delete } from '~/client/util/apiv3-client';
-import { useEmptyTrashModal } from '~/stores/modal';
+import { useEmptyTrashModalStatus, useEmptyTrashModalActions } from '~/states/ui/modal/empty-trash';
 
 import ApiErrorMessageList from './PageManagement/ApiErrorMessageList';
 
 const EmptyTrashModal: FC = () => {
   const { t } = useTranslation();
 
-  const { data: emptyTrashModalData, close: closeEmptyTrashModal } = useEmptyTrashModal();
+  const emptyTrashModalData = useEmptyTrashModalStatus();
+  const { close: closeEmptyTrashModal } = useEmptyTrashModalActions();
 
   const isOpened = emptyTrashModalData?.isOpened ?? false;
 

+ 2 - 2
apps/app/src/client/components/TrashPageList.tsx

@@ -9,7 +9,7 @@ import { toastSuccess } from '~/client/util/toastr';
 import type { IPagingResult } from '~/interfaces/paging-result';
 import { useIsReadOnlyUser } from '~/states/context';
 import { showPageLimitationXLAtom } from '~/states/server-configurations';
-import { useEmptyTrashModal } from '~/stores/modal';
+import { useEmptyTrashModalActions } from '~/states/ui/modal/empty-trash';
 import { useSWRxPageInfoForList, useSWRxPageList } from '~/stores/page-listing';
 
 import { MenuItemType } from './Common/Dropdown/PageItemControl';
@@ -30,7 +30,7 @@ const useEmptyTrashButton = () => {
   const limit = useAtomValue(showPageLimitationXLAtom);
   const isReadOnlyUser = useIsReadOnlyUser();
   const { data: pagingResult, mutate: mutatePageLists } = useSWRxPageList('/trash', 1, limit);
-  const { open: openEmptyTrashModal } = useEmptyTrashModal();
+  const { open: openEmptyTrashModal } = useEmptyTrashModalActions();
 
   const pageIds = pagingResult?.items?.map(page => page._id);
   const { injectTo } = useSWRxPageInfoForList(pageIds, null, true, true);

+ 59 - 0
apps/app/src/states/ui/modal/empty-trash.ts

@@ -0,0 +1,59 @@
+import type { IPageToDeleteWithMeta } from '@growi/core';
+import { atom, useAtomValue, useSetAtom } from 'jotai';
+import { useCallback } from 'react';
+
+type IEmptyTrashModalOption = {
+  onEmptiedTrash?: () => void;
+  canDeleteAllPages: boolean;
+};
+
+export type EmptyTrashModalStatus = {
+  isOpened: boolean;
+  pages?: IPageToDeleteWithMeta[];
+  opts?: IEmptyTrashModalOption;
+};
+
+export type EmptyTrashModalActions = {
+  open: (
+    pages?: IPageToDeleteWithMeta[],
+    opts?: IEmptyTrashModalOption,
+  ) => void;
+  close: () => void;
+};
+
+// Atom for empty trash modal state
+const emptyTrashModalAtom = atom<EmptyTrashModalStatus>({
+  isOpened: false,
+  pages: [],
+});
+
+/**
+ * Hook for managing empty trash modal state
+ * Returns read-only modal status for optimal performance
+ * Used for displaying modal state without triggering unnecessary re-renders
+ */
+export const useEmptyTrashModalStatus = (): EmptyTrashModalStatus => {
+  return useAtomValue(emptyTrashModalAtom);
+};
+
+/**
+ * Hook for managing empty trash modal actions
+ * Returns actions for opening and closing the modal with stable references
+ * Optimized to prevent unnecessary re-renders in action-only components
+ */
+export const useEmptyTrashModalActions = (): EmptyTrashModalActions => {
+  const setStatus = useSetAtom(emptyTrashModalAtom);
+
+  const open = useCallback(
+    (pages?: IPageToDeleteWithMeta[], opts?: IEmptyTrashModalOption) => {
+      setStatus({ isOpened: true, pages, opts });
+    },
+    [setStatus],
+  );
+
+  const close = useCallback(() => {
+    setStatus({ isOpened: false, pages: [], opts: undefined });
+  }, [setStatus]);
+
+  return { open, close };
+};

+ 1 - 43
apps/app/src/stores/modal.tsx

@@ -1,7 +1,7 @@
 import { useCallback, useMemo } from 'react';
 
 import type {
-  IAttachmentHasId, IPageToDeleteWithMeta, IUserGroupHasId,
+  IAttachmentHasId, IUserGroupHasId,
 } from '@growi/core';
 import { useSWRStatic } from '@growi/core/dist/swr';
 import { MarkdownTable } from '@growi/editor';
@@ -47,48 +47,6 @@ export const useGrantedGroupsInheritanceSelectModal = (
   };
 };
 
-/*
-* EmptyTrashModal
-*/
-type IEmptyTrashModalOption = {
-  onEmptiedTrash?: () => void,
-  canDeleteAllPages: boolean,
-}
-
-type EmptyTrashModalStatus = {
-  isOpened: boolean,
-  pages?: IPageToDeleteWithMeta[],
-  opts?: IEmptyTrashModalOption,
-}
-
-type EmptyTrashModalStatusUtils = {
-  open(
-    pages?: IPageToDeleteWithMeta[],
-    opts?: IEmptyTrashModalOption,
-  ): Promise<EmptyTrashModalStatus | undefined>,
-  close(): Promise<EmptyTrashModalStatus | undefined>,
-}
-
-export const useEmptyTrashModal = (status?: EmptyTrashModalStatus): SWRResponse<EmptyTrashModalStatus, Error> & EmptyTrashModalStatusUtils => {
-  const initialData: EmptyTrashModalStatus = {
-    isOpened: false,
-    pages: [],
-  };
-  const swrResponse = useSWRStatic<EmptyTrashModalStatus, Error>('emptyTrashModalStatus', status, { fallbackData: initialData });
-
-  return {
-    ...swrResponse,
-    open: (
-        pages?: IPageToDeleteWithMeta[],
-        opts?: IEmptyTrashModalOption,
-    ) => swrResponse.mutate({
-      isOpened: true, pages, opts,
-    }),
-    close: () => swrResponse.mutate({ isOpened: false }),
-  };
-};
-
-
 /*
 * PutBackPageModal
 */