ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Next.js] URL query string 관리하기
    Next.js 2023. 4. 10. 23:57

    Next.js 13의 useSearchParams hook은 현재 URL의 query string을 읽을 수 있게 해주는 hook으로, read-only 버전의 URLSearchParams 인터페이스를 return합니다. useSearchParams hook의 사용 방법은 아래와 같습니다.

     

    // url: /?note=4%7C10
    import { useSearchParams } from 'next/navigation';
    
    const searchParams = useSearchParams();
    
    console.log(searchParams.get('note')); // 4|10
    console.log(searchParams.has('note')); // true
    console.log(searchParams.has('brand')); // false

     

    그러나 Next.js의 useSearchParams hook은 read-only입니다. 때문에 공식 문서에서는 query string을 추가하고, 업데이트하고, 삭제하기 위해서는 URLSearchParams 인터페이스를 활용하는 방식을 예시로 제시하고 있었습니다. 

     

    // Next.js 공식문서의 Updating searchParams 예시
    export default function ExampleClientComponent() {
      const router = useRouter()
      const pathname = usePathname()
      const searchParams = useSearchParams()!
     
      // Get a new searchParams string by merging the current
      // searchParams with a provided key/value pair
      const createQueryString = useCallback(
        (name: string, value: string) => {
          const params = new URLSearchParams(searchParams)
          params.set(name, value)
     
          return params.toString()
        },
        [searchParams]
      )
     
      return (
        <>
          <p>Sort By</p>
     
          {/* using useRouter */}
          <button
            onClick={() => {
              // <pathname>?sort=asc
              router.push(pathname + '?' + createQueryString('sort', 'asc'))
            }}
          >
            ASC
          </button>
     
          {/* using <Link> */}
          <Link
            href={
              // <pathname>?sort=desc
              pathname + '?' + createQueryString('sort', 'desc')
            }
          >
            DESC
          </Link>
        </>
      )
    }

     

    이러한 예시와 검색 결과를 바탕으로 아래와 같은 cutom hook을 만들었습니다.

     

     

    import { usePathname, useRouter, useSearchParams } from 'next/navigation';
    
    function useCustomSearchParams<T extends Partial<{ [key: string]: string[] | undefined }>>() {
      const searchParams = useSearchParams();
      const pathname = usePathname();
      const router = useRouter();
      const urlSearchParams = searchParams ? new URLSearchParams(searchParams) : null;
    
      function setSearchParams(params: Partial<T>) {
        Object.entries(params).forEach(([key, value]) => {
          if (!value.length) urlSearchParams?.delete(key);
          else urlSearchParams?.set(key, String(value.join('|')));
        });
    
        const paramsToString = urlSearchParams?.toString();
        const query = paramsToString ? `?${paramsToString}` : '';
        
        router.push(`${pathname}${query}`);
      }
    
      return { searchParams, setSearchParams };
    }
    
    export default useCustomSearchParams;

     

    위의 hook은 query string을 활용하여 필터 기능을 구현하기 위해 만들었는데, 관리해야 하는 필터의 항목이 두 개 였기 때문에 setSearchParams 함수에 객체 형태의 parameter를 전달할 수 있도록 구현했습니다.

    이 때 setSearchParams 함수는 parameter로 전달 받은 객체를 순회하며 key에 해당하는 value의 length가 1 이상일 경우 urlSearchParams에 key, value를 set 하고, value의 length가 0일 경우 urlSearchParams에서 key를 삭제합니다. 

    이후 urlSearchParams를 string 형태로 변환하고, 이를 pathname과 함께 router에 push해 주면 "/?brand=1%7C2&note=4" 의 형태로 URL을 관리할 수 있습니다.

     

    참고 자료

    - https://nextjs.org/docs/app/api-reference/functions/use-search-params

    - https://developer.mozilla.org/ko/docs/Web/API/URLSearchParams

    - https://github.com/vercel/next.js/discussions/47583

    댓글

Designed by Tistory.