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

refactor updating useSWRxCurrentPage and useEditingMarkdown

Yuki Takei 3 лет назад
Родитель
Сommit
344e265c0f

+ 10 - 4
packages/app/src/components/ContentLinkButtons.tsx

@@ -1,8 +1,9 @@
 import React, { useCallback } from 'react';
 import React, { useCallback } from 'react';
 
 
+import { IUser } from '@growi/core';
+
 import { smoothScrollIntoView } from '~/client/util/smooth-scroll';
 import { smoothScrollIntoView } from '~/client/util/smooth-scroll';
 import { RecentlyCreatedIcon } from '~/components/Icons/RecentlyCreatedIcon';
 import { RecentlyCreatedIcon } from '~/components/Icons/RecentlyCreatedIcon';
-import { usePageUser } from '~/stores/context';
 
 
 import styles from './ContentLinkButtons.module.scss';
 import styles from './ContentLinkButtons.module.scss';
 
 
@@ -52,11 +53,16 @@ const RecentlyCreatedLinkButton = React.memo(() => {
 
 
 RecentlyCreatedLinkButton.displayName = 'RecentlyCreatedLinkButton';
 RecentlyCreatedLinkButton.displayName = 'RecentlyCreatedLinkButton';
 
 
-export const ContentLinkButtons = (): JSX.Element => {
 
 
-  const { data: pageUser } = usePageUser();
+type Props = {
+  author?: IUser,
+}
+
+export const ContentLinkButtons = (props: Props): JSX.Element => {
+
+  const { author } = props;
 
 
-  if (pageUser == null || pageUser.status === 4) {
+  if (author == null || author.status === 4) {
     return <></>;
     return <></>;
   }
   }
 
 

+ 2 - 2
packages/app/src/components/Page/DisplaySwitcher.tsx

@@ -49,7 +49,7 @@ const PageView = React.memo((): JSX.Element => {
     <div className="d-flex flex-column flex-lg-row">
     <div className="d-flex flex-column flex-lg-row">
 
 
       <div className="flex-grow-1 flex-basis-0 mw-0">
       <div className="flex-grow-1 flex-basis-0 mw-0">
-        { isUsersHomePagePath && <UserInfo /> }
+        { isUsersHomePagePath && <UserInfo author={currentPage?.creator} /> }
         { !isNotFound && <Page /> }
         { !isNotFound && <Page /> }
         { isNotFound && <NotFoundPage /> }
         { isNotFound && <NotFoundPage /> }
       </div>
       </div>
@@ -94,7 +94,7 @@ const PageView = React.memo((): JSX.Element => {
 
 
             <div className="d-none d-lg-block">
             <div className="d-none d-lg-block">
               <TableOfContents />
               <TableOfContents />
-              { isUsersHomePagePath && <ContentLinkButtons /> }
+              { isUsersHomePagePath && <ContentLinkButtons author={currentPage?.creator} /> }
             </div>
             </div>
 
 
           </div>
           </div>

+ 3 - 1
packages/app/src/components/PageCreateModal.jsx

@@ -5,6 +5,7 @@ import React, {
 import { pagePathUtils, pathUtils } from '@growi/core';
 import { pagePathUtils, pathUtils } from '@growi/core';
 import { format } from 'date-fns';
 import { format } from 'date-fns';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
+import { useRouter } from 'next/router';
 import { Modal, ModalHeader, ModalBody } from 'reactstrap';
 import { Modal, ModalHeader, ModalBody } from 'reactstrap';
 import { debounce } from 'throttle-debounce';
 import { debounce } from 'throttle-debounce';
 
 
@@ -21,6 +22,7 @@ const {
 
 
 const PageCreateModal = () => {
 const PageCreateModal = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
+  const router = useRouter();
 
 
   const { data: currentUser } = useCurrentUser();
   const { data: currentUser } = useCurrentUser();
 
 
@@ -98,7 +100,7 @@ const PageCreateModal = () => {
   async function redirectToEditor(...paths) {
   async function redirectToEditor(...paths) {
     try {
     try {
       const editorPath = await generateEditorPath(...paths);
       const editorPath = await generateEditorPath(...paths);
-      window.location.href = editorPath;
+      router.push(editorPath);
     }
     }
     catch (err) {
     catch (err) {
       toastError(err);
       toastError(err);

+ 6 - 4
packages/app/src/components/PageEditor.tsx

@@ -13,7 +13,8 @@ import { apiGet, apiPostForm } from '~/client/util/apiv1-client';
 import { getOptionsToSave } from '~/client/util/editor';
 import { getOptionsToSave } from '~/client/util/editor';
 import { IEditorMethods } from '~/interfaces/editor-methods';
 import { IEditorMethods } from '~/interfaces/editor-methods';
 import {
 import {
-  useIsEditable, useIsIndentSizeForced, useCurrentPagePath, useCurrentPathname, useCurrentPageId, useIsUploadableFile, useIsUploadableImage,
+  useCurrentPagePath, useCurrentPathname, useCurrentPageId, useEditingMarkdown,
+  useIsEditable, useIsIndentSizeForced, useIsUploadableFile, useIsUploadableImage,
 } from '~/stores/context';
 } from '~/stores/context';
 import {
 import {
   useCurrentIndentSize, useSWRxSlackChannels, useIsSlackEnabled, useIsTextlintEnabled, usePageTagsForEditors,
   useCurrentIndentSize, useSWRxSlackChannels, useIsSlackEnabled, useIsTextlintEnabled, usePageTagsForEditors,
@@ -51,6 +52,7 @@ const PageEditor = React.memo((): JSX.Element => {
   const { data: currentPagePath } = useCurrentPagePath();
   const { data: currentPagePath } = useCurrentPagePath();
   const { data: currentPathname } = useCurrentPathname();
   const { data: currentPathname } = useCurrentPathname();
   const { data: currentPage, mutate: mutateCurrentPage } = useSWRxCurrentPage();
   const { data: currentPage, mutate: mutateCurrentPage } = useSWRxCurrentPage();
+  const { data: editingMarkdown } = useEditingMarkdown();
   const { data: grantData, mutate: mutateGrant } = useSelectedGrant();
   const { data: grantData, mutate: mutateGrant } = useSelectedGrant();
   const { data: pageTags } = usePageTagsForEditors(pageId);
   const { data: pageTags } = usePageTagsForEditors(pageId);
 
 
@@ -69,10 +71,10 @@ const PageEditor = React.memo((): JSX.Element => {
   const { data: rendererOptions } = usePreviewOptions();
   const { data: rendererOptions } = usePreviewOptions();
 
 
   const currentRevisionId = currentPage?.revision?._id;
   const currentRevisionId = currentPage?.revision?._id;
-  const initialValue = currentPage?.revision?.body;
+  const initialValue = editingMarkdown ?? '';
 
 
-  const markdownToSave = useRef<string>(initialValue ?? '');
-  const [markdownToPreview, setMarkdownToPreview] = useState<string>(initialValue ?? '');
+  const markdownToSave = useRef<string>(initialValue);
+  const [markdownToPreview, setMarkdownToPreview] = useState<string>(initialValue);
 
 
   const slackChannels = useMemo(() => (slackChannelsData ? slackChannelsData.toString() : ''), [slackChannelsData]);
   const slackChannels = useMemo(() => (slackChannelsData ? slackChannelsData.toString() : ''), [slackChannelsData]);
 
 

+ 16 - 12
packages/app/src/components/User/UserInfo.tsx

@@ -1,37 +1,41 @@
 import React from 'react';
 import React from 'react';
 
 
+import { IUser } from '@growi/core';
 import { UserPicture } from '@growi/ui';
 import { UserPicture } from '@growi/ui';
 
 
-import { usePageUser } from '~/stores/context';
-
 import styles from './UserInfo.module.scss';
 import styles from './UserInfo.module.scss';
 
 
-export const UserInfo = (): JSX.Element => {
 
 
-  const { data: pageUser } = usePageUser();
+type Props = {
+  author?: IUser,
+}
+
+export const UserInfo = (props: Props): JSX.Element => {
+
+  const { author } = props;
 
 
-  if (pageUser == null || pageUser.status === 4) {
+  if (author == null || author.status === 4) {
     return <></>;
     return <></>;
   }
   }
 
 
   return (
   return (
     <div className={`${styles['grw-users-info']} grw-users-info d-flex align-items-center d-edit-none mb-5 pb-3 border-bottom`}>
     <div className={`${styles['grw-users-info']} grw-users-info d-flex align-items-center d-edit-none mb-5 pb-3 border-bottom`}>
-      <UserPicture user={pageUser} />
+      <UserPicture user={author} />
       <div className="users-meta">
       <div className="users-meta">
         <h1 className="user-page-name">
         <h1 className="user-page-name">
-          {pageUser.name}
+          {author.name}
         </h1>
         </h1>
         <div className="user-page-meta mt-3 mb-0">
         <div className="user-page-meta mt-3 mb-0">
-          <span className="user-page-username mr-4"><i className="icon-user mr-1"></i>{pageUser.username}</span>
+          <span className="user-page-username mr-4"><i className="icon-user mr-1"></i>{author.username}</span>
           <span className="user-page-email mr-2">
           <span className="user-page-email mr-2">
             <i className="icon-envelope mr-1"></i>
             <i className="icon-envelope mr-1"></i>
-            { pageUser.isEmailPublished
-              ? pageUser.email
+            { author.isEmailPublished
+              ? author.email
               : '*****'
               : '*****'
             }
             }
           </span>
           </span>
-          { pageUser.introduction && (
-            <span className="user-page-introduction">{pageUser.introduction}</span>
+          { author.introduction && (
+            <span className="user-page-introduction">{author.introduction}</span>
           ) }
           ) }
         </div>
         </div>
       </div>
       </div>

+ 11 - 13
packages/app/src/pages/[[...path]].page.tsx

@@ -62,7 +62,7 @@ import {
   useIsAclEnabled, useIsUserPage,
   useIsAclEnabled, useIsUserPage,
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
   useIsSlackConfigured, useRendererConfig, useEditingMarkdown,
   useIsSlackConfigured, useRendererConfig, useEditingMarkdown,
-  useEditorConfig, useIsAllReplyShown, useIsUploadableFile, useIsUploadableImage, usePageUser,
+  useEditorConfig, useIsAllReplyShown, useIsUploadableFile, useIsUploadableImage,
 } from '../stores/context';
 } from '../stores/context';
 
 
 import {
 import {
@@ -126,7 +126,7 @@ const PutbackPageModal = (): JSX.Element => {
 type Props = CommonProps & {
 type Props = CommonProps & {
   currentUser: IUser,
   currentUser: IUser,
 
 
-  pageWithMeta: IPageToShowRevisionWithMeta,
+  pageWithMeta: IPageToShowRevisionWithMeta | null,
   // pageUser?: any,
   // pageUser?: any,
   redirectFrom?: string;
   redirectFrom?: string;
 
 
@@ -231,27 +231,25 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
 
 
   const { pageWithMeta, userUISettings } = props;
   const { pageWithMeta, userUISettings } = props;
 
 
-  let shouldRenderPutbackPageModal = false;
-  if (pageWithMeta != null) {
-    shouldRenderPutbackPageModal = _isTrashPage(pageWithMeta.data.path);
-  }
+  useSWRxCurrentPage(undefined, pageWithMeta?.data ?? null); // store initial data
+  useEditingMarkdown(pageWithMeta?.data.revision?.body ?? '');
 
 
   const pageId = pageWithMeta?.data._id;
   const pageId = pageWithMeta?.data._id;
   const pagePath = pageWithMeta?.data.path ?? (!_isPermalink(props.currentPathname) ? props.currentPathname : undefined);
   const pagePath = pageWithMeta?.data.path ?? (!_isPermalink(props.currentPathname) ? props.currentPathname : undefined);
 
 
-  useCurrentPageId(pageId);
-  useSWRxCurrentPage(undefined, pageWithMeta?.data); // store initial data
+  useCurrentPageId(pageId ?? null);
   useIsUserPage(pagePath != null && isUserPage(pagePath));
   useIsUserPage(pagePath != null && isUserPage(pagePath));
   // useIsNotCreatable(props.isForbidden || !isCreatablePage(pagePath)); // TODO: need to include props.isIdentical
   // useIsNotCreatable(props.isForbidden || !isCreatablePage(pagePath)); // TODO: need to include props.isIdentical
   useCurrentPagePath(pagePath);
   useCurrentPagePath(pagePath);
   useCurrentPathname(props.currentPathname);
   useCurrentPathname(props.currentPathname);
-  useEditingMarkdown(pageWithMeta?.data.revision?.body);
   useIsTrashPage(pagePath != null && _isTrashPage(pagePath));
   useIsTrashPage(pagePath != null && _isTrashPage(pagePath));
 
 
   const { data: grantData } = useSWRxIsGrantNormalized(pageId);
   const { data: grantData } = useSWRxIsGrantNormalized(pageId);
   const { mutate: mutateSelectedGrant } = useSelectedGrant();
   const { mutate: mutateSelectedGrant } = useSelectedGrant();
 
 
-  usePageUser(pageWithMeta?.data.creator);
+  const shouldRenderPutbackPageModal = pageWithMeta != null
+    ? _isTrashPage(pageWithMeta.data.path)
+    : false;
 
 
   // sync grant data
   // sync grant data
   useEffect(() => {
   useEffect(() => {
@@ -329,8 +327,8 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
           </div>
           </div>
           { !props.isIdenticalPathPage && !props.isNotFound && (
           { !props.isIdenticalPathPage && !props.isNotFound && (
             <footer className="footer d-edit-none">
             <footer className="footer d-edit-none">
-              { !isTopPagePath && (<Comments pageId={pageId} revision={pageWithMeta?.data.revision} />) }
-              { (pageWithMeta != null && isUsersHomePage(pageWithMeta.data.path)) && (
+              { pageWithMeta != null && !isTopPagePath && (<Comments pageId={pageId} revision={pageWithMeta?.data.revision} />) }
+              { pageWithMeta != null && isUsersHomePage(pageWithMeta.data.path) && (
                 <UsersHomePageFooter creatorId={pageWithMeta.data.creator._id}/>
                 <UsersHomePageFooter creatorId={pageWithMeta.data.creator._id}/>
               ) }
               ) }
               <CurrentPageContentFooter />
               <CurrentPageContentFooter />
@@ -396,7 +394,7 @@ async function injectPageData(context: GetServerSidePropsContext, props: Props):
     }
     }
   }
   }
 
 
-  const pageWithMeta: IPageToShowRevisionWithMeta = await pageService.findPageAndMetaDataByViewer(pageId, currentPathname, user, true); // includeEmpty = true, isSharedPage = false
+  const pageWithMeta: IPageToShowRevisionWithMeta | null = await pageService.findPageAndMetaDataByViewer(pageId, currentPathname, user, true); // includeEmpty = true, isSharedPage = false
   const page = pageWithMeta?.data as unknown as PageDocument;
   const page = pageWithMeta?.data as unknown as PageDocument;
 
 
   // add user to seen users
   // add user to seen users

+ 0 - 4
packages/app/src/stores/context.tsx

@@ -98,10 +98,6 @@ export const useIsNotFound = (initialData?: boolean): SWRResponse<boolean, Error
   return useStaticSWR<boolean, Error>('isNotFound', initialData, { fallbackData: false });
   return useStaticSWR<boolean, Error>('isNotFound', initialData, { fallbackData: false });
 };
 };
 
 
-export const usePageUser = (initialData?: IUserHasId): SWRResponse<IUserHasId, Error> => {
-  return useStaticSWR<IUserHasId, Error>('pageUser', initialData);
-};
-
 export const useHasChildren = (initialData?: Nullable<any>): SWRResponse<Nullable<any>, Error> => {
 export const useHasChildren = (initialData?: Nullable<any>): SWRResponse<Nullable<any>, Error> => {
   return useStaticSWR<Nullable<any>, Error>('hasChildren', initialData);
   return useStaticSWR<Nullable<any>, Error>('hasChildren', initialData);
 };
 };

+ 4 - 2
packages/app/src/stores/page.tsx

@@ -39,14 +39,16 @@ export const useSWRxPageByPath = (path?: string): SWRResponse<IPagePopulatedToSh
   );
   );
 };
 };
 
 
-export const useSWRxCurrentPage = (shareLinkId?: string, initialData?: IPagePopulatedToShowRevision): SWRResponse<IPagePopulatedToShowRevision|null, Error> => {
+export const useSWRxCurrentPage = (
+    shareLinkId?: string, initialData?: IPagePopulatedToShowRevision|null,
+): SWRResponse<IPagePopulatedToShowRevision|null, Error> => {
   const { data: currentPageId } = useCurrentPageId();
   const { data: currentPageId } = useCurrentPageId();
 
 
   const swrResult = useSWRxPage(currentPageId, shareLinkId);
   const swrResult = useSWRxPage(currentPageId, shareLinkId);
 
 
   // use mutate because fallbackData does not work
   // use mutate because fallbackData does not work
   // see: https://github.com/weseek/growi/commit/5038473e8d6028c9c91310e374a7b5f48b921a15
   // see: https://github.com/weseek/growi/commit/5038473e8d6028c9c91310e374a7b5f48b921a15
-  if (initialData != null) {
+  if (initialData !== undefined) {
     swrResult.mutate(initialData);
     swrResult.mutate(initialData);
   }
   }