[Next.js] URL query string 관리하기
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¬e=4" 의 형태로 URL을 관리할 수 있습니다.
참고 자료
- https://nextjs.org/docs/app/api-reference/functions/use-search-params
- https://developer.mozilla.org/ko/docs/Web/API/URLSearchParams