Yuki Takei пре 2 година
родитељ
комит
646c058c20

+ 17 - 14
apps/app/src/client/services/search-operation.ts

@@ -1,15 +1,15 @@
-import {
-  useCallback, useEffect, useRef, useState,
-} from 'react';
+import { useCallback, useEffect, useRef } from 'react';
 
+import { type SWRResponseWithUtils, withUtils } from '@growi/core';
 import { useRouter } from 'next/router';
+import useSWRImmutable from 'swr/immutable';
+
 
 type UseSearchOperation = {
-  keyword: string,
   search: (newKeyword: string, ignorePushingState?: boolean) => void,
 }
 
-export const useSearchOperation = (): UseSearchOperation => {
+export const useSearchOperation = (): SWRResponseWithUtils<UseSearchOperation, string> => {
   // routerRef solve the problem of infinite redrawing that occurs with routers
   const router = useRouter();
   const routerRef = useRef(router);
@@ -18,17 +18,21 @@ export const useSearchOperation = (): UseSearchOperation => {
   const queries = router.query.q;
   const initialKeyword = (Array.isArray(queries) ? queries.join(' ') : queries) ?? '';
 
-  const [keyword, setKeyword] = useState(initialKeyword);
+  const swrResponse = useSWRImmutable<string>('searchKeyword', null, {
+    fallbackData: initialKeyword,
+  });
 
+  const { mutate } = swrResponse;
   const search = useCallback((newKeyword: string, ignorePushingState?: boolean) => {
-    setKeyword(newKeyword);
+    mutate(newKeyword);
 
     if (ignorePushingState !== true) {
       const newUrl = new URL('/_search', 'http://example.com');
       newUrl.searchParams.append('q', newKeyword);
-      routerRef.current.push(`${newUrl.pathname}${newUrl.search}`, '', { shallow: true });
+      // routerRef.current.push(`${newUrl.pathname}${newUrl.search}`, '', { shallow: true });
+      routerRef.current.push(`${newUrl.pathname}${newUrl.search}`, '');
     }
-  }, []);
+  }, [mutate]);
 
   // browser back and forward
   useEffect(() => {
@@ -36,14 +40,13 @@ export const useSearchOperation = (): UseSearchOperation => {
       const newUrl = new URL(url, 'https://exmple.com');
       const newKeyword = newUrl.searchParams.get('q');
       if (newKeyword != null) {
-        setKeyword(newKeyword);
+        mutate(newKeyword);
       }
       return true;
     });
-  }, [setKeyword, routerRef]);
+  }, [mutate]);
 
-  return {
-    keyword,
+  return withUtils(swrResponse, {
     search,
-  };
+  });
 };

+ 5 - 4
apps/app/src/components/SearchPage.tsx

@@ -91,7 +91,7 @@ export const SearchPage = (): JSX.Element => {
   const { t } = useTranslation();
   const { data: showPageLimitationL } = useShowPageLimitationL();
 
-  const { keyword, search } = useSearchOperation();
+  const { data: keyword, search } = useSearchOperation();
 
   const [offset, setOffset] = useState<number>(0);
   const [limit, setLimit] = useState<number>(showPageLimitationL ?? INITIAL_PAGIONG_SIZE);
@@ -101,7 +101,7 @@ export const SearchPage = (): JSX.Element => {
 
   const { data: isSearchServiceReachable } = useIsSearchServiceReachable();
 
-  const { data, conditions, mutate } = useSWRxSearch(keyword, null, {
+  const { data, conditions, mutate } = useSWRxSearch(keyword ?? '', null, {
     ...configurationsByControl,
     offset,
     limit,
@@ -113,7 +113,8 @@ export const SearchPage = (): JSX.Element => {
 
     const ignorePushingState = keyword === newKeyword;
     search(newKeyword, ignorePushingState);
-  }, [keyword, search]);
+    mutate();
+  }, [keyword, mutate, search]);
 
   const selectAllCheckboxChangedHandler = useCallback((isChecked: boolean) => {
     const instance = searchPageBaseRef.current;
@@ -220,7 +221,7 @@ export const SearchPage = (): JSX.Element => {
     return (
       <SearchResultListHead
         searchResult={data}
-        searchingKeyword={keyword}
+        searchingKeyword={keyword ?? ''}
         offset={offset}
         pagingSize={limit}
         onPagingSizeChanged={pagingSizeChangedHandler}

+ 11 - 15
apps/app/src/components/TagList.tsx

@@ -3,8 +3,8 @@ import React, {
 } from 'react';
 
 import { useTranslation } from 'next-i18next';
-import Link from 'next/link';
 
+import { useSearchOperation } from '~/client/services/search-operation';
 import { IDataTagCount } from '~/interfaces/tag';
 
 import PaginationWrapper from './PaginationWrapper';
@@ -29,26 +29,22 @@ const TagList: FC<TagListProps> = (props:(TagListProps & typeof defaultProps)) =
   const isTagExist: boolean = tagData.length > 0;
   const { t } = useTranslation('');
 
-  const generateTagList = useCallback((tagData) => {
-    return tagData.map((tag:IDataTagCount, index:number) => {
-      const tagListClasses: string = index === 0 ? 'list-group-item d-flex' : 'list-group-item d-flex border-top-0';
-
-      const url = new URL('/_search', 'https://example.com');
-      url.searchParams.append('q', `tag:${tag.name}`);
+  const { search } = useSearchOperation();
 
+  const generateTagList = useCallback((tagData) => {
+    return tagData.map((tag:IDataTagCount) => {
       return (
-        <Link
+        <button
           key={tag._id}
-          href={`${url.pathname}${url.search}`}
-          className={tagListClasses}
-          prefetch={false}
+          className="list-group-item list-group-item-action d-flex"
+          onClick={() => search(`tag:${tag.name}`)}
         >
           <div className="text-truncate list-tag-name">{tag.name}</div>
           <div className="ml-4 my-auto py-1 px-2 list-tag-count badge badge-secondary text-white">{tag.count}</div>
-        </Link>
+        </button>
       );
     });
-  }, []);
+  }, [search]);
 
   if (!isTagExist) {
     return <h3>{ t('You have no tag, You can set tags on pages') }</h3>;
@@ -56,9 +52,9 @@ const TagList: FC<TagListProps> = (props:(TagListProps & typeof defaultProps)) =
 
   return (
     <>
-      <ul className="list-group text-left mb-5">
+      <div className="list-group text-left mb-5">
         {generateTagList(tagData)}
-      </ul>
+      </div>
       {isPaginationShown
       && (
         <PaginationWrapper