search-operation.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import { useCallback, useEffect, useRef } from 'react';
  2. import { type SWRResponseWithUtils, withUtils } from '@growi/core/dist/swr';
  3. import { useRouter } from 'next/router';
  4. import useSWRImmutable from 'swr/immutable';
  5. type UseKeywordManagerUtils = {
  6. pushState: (newKeyword: string) => void,
  7. }
  8. export const useKeywordManager = (): SWRResponseWithUtils<UseKeywordManagerUtils, string> => {
  9. // routerRef solve the problem of infinite redrawing that occurs with routers
  10. const router = useRouter();
  11. const routerRef = useRef(router);
  12. // parse URL Query
  13. const queries = router.query.q;
  14. const initialKeyword = (Array.isArray(queries) ? queries.join(' ') : queries) ?? '';
  15. const swrResponse = useSWRImmutable<string>('searchKeyword', null, {
  16. fallbackData: initialKeyword,
  17. });
  18. const { mutate } = swrResponse;
  19. const pushState = useCallback((newKeyword: string) => {
  20. mutate((prevKeyword) => {
  21. if (prevKeyword !== newKeyword) {
  22. const newUrl = new URL('/_search', 'http://example.com');
  23. newUrl.searchParams.append('q', newKeyword);
  24. routerRef.current.push(`${newUrl.pathname}${newUrl.search}`, '');
  25. }
  26. return newKeyword;
  27. });
  28. }, [mutate]);
  29. // detect search keyword from the query of URL
  30. useEffect(() => {
  31. mutate(initialKeyword);
  32. }, [mutate, initialKeyword]);
  33. // browser back and forward
  34. useEffect(() => {
  35. routerRef.current.beforePopState(({ url }) => {
  36. const newUrl = new URL(url, 'https://exmple.com');
  37. const newKeyword = newUrl.searchParams.get('q');
  38. if (newKeyword != null) {
  39. mutate(newKeyword);
  40. }
  41. return true;
  42. });
  43. }, [mutate]);
  44. return withUtils(swrResponse, {
  45. pushState,
  46. });
  47. };