본문 바로가기

개발 공부/React

Next.js usePathname, useRouter, useSearchParams

코드 출처 : https://github.com/Cluster-Taek/next14-boilerplate

 

GitHub - Cluster-Taek/next14-boilerplate

Contribute to Cluster-Taek/next14-boilerplate development by creating an account on GitHub.

github.com

 

use-query-string.ts

import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useCallback } from 'react';

interface UpdateQueryStringOption {
  replace?: boolean;
}
export const useQueryString = () => {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();

  const updateQueryString = useCallback(
    (name: string, value: string, options?: UpdateQueryStringOption) => {
      const params = new URLSearchParams(searchParams.toString());
      params.set(name, value);

      debugger;

      if (options?.replace) {
        router.replace(pathname + '?' + params.toString());
      } else {
        router.push(pathname + '?' + params.toString());
      }
    },
    [searchParams, router, pathname]
  );

  return { updateQueryString } as const;
};

 

 

 

import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useCallback } from "react";

 

  • usePathname: 현재 페이지의 경로(pathname)를 반환합니다. 예: /home, /about.
  • useRouter: 라우터 객체를 가져옵니다. 이를 통해 페이지 이동(push 또는 replace)을 수행할 수 있습니다.
  • useSearchParams: 현재 URL의 쿼리 문자열(search params)을 가져옵니다.
  • useCallback: 함수 메모이제이션을 제공하는 React 훅으로, 불필요한 재생성을 방지합니다.

 

interface UpdateQueryStringOption {
  replace?: boolean;
}

 

  • replace 옵션: URL 변경 시 router.replace를 사용할지(true), 아니면 router.push를 사용할지(false 기본값)를 결정합니다.

 

export const useQueryString = () => {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();

 

  • router: 페이지 이동 및 URL 변경을 담당합니다.
  • pathname: 현재 경로를 나타냅니다.
  • searchParams: 현재 URL의 쿼리 파라미터를 나타냅니다.

 

 

const updateQueryString = useCallback(
  (name: string, value: string, options?: UpdateQueryStringOption) => {
    const params = new URLSearchParams(searchParams.toString());
    params.set(name, value);

 

  • name, value: 업데이트할 쿼리 파라미터의 이름과 값을 받습니다.
  • options: replace 여부를 포함하는 선택적 옵션 객체입니다.
  • new URLSearchParams(searchParams.toString()): 현재 쿼리 문자열을 복사하여 URLSearchParams 객체로 만듭니다. 이를 통해 수정이 가능합니다.
  • params.set(name, value): 지정된 이름의 쿼리 파라미터를 업데이트하거나 추가합니다.

 

if (options?.replace) {
  router.replace(pathname + "?" + params.toString());
} else {
  router.push(pathname + "?" + params.toString());
}

 

 

 

  • options?.replace:
    • true: router.replace를 사용하여 현재 페이지의 URL을 변경합니다. 브라우저 히스토리 스택에 기록되지 않습니다.
    • false(기본값): router.push를 사용하여 URL을 변경합니다. 브라우저 히스토리 스택에 기록됩니다.
  • pathname + "?" + params.toString(): 새로운 경로와 쿼리 문자열을 결합합니다.

 

return { updateQueryString } as const;

 

  • updateQueryString 함수만 반환하며, 이를 상수(as const)로 고정하여 호출 시 타입 안정성을 제공합니다.

 

이 함수는 쿼리 문자열(query string)을 동적으로 업데이트해야 하는 경우에 유용합니다.

특히 Next.js 애플리케이션에서 URL 상태를 관리하거나, 필터링, 페이징, 정렬 등과 같은 동작을 처리할 때 자주 사용됩니다.

 

1. 검색 필터링 기능

사용자가 검색 조건을 변경할 때 URL에 필터 조건을 반영해야 하는 경우:

  • 예: 검색 페이지에서 category=electronics와 같은 조건을 URL에 추가.
const { updateQueryString } = useQueryString();

const handleCategoryChange = (category: string) => {
  updateQueryString("category", category);
};

 

 

2. 페이지네이션 (Pagination)

사용자가 다른 페이지로 이동할 때 쿼리 파라미터로 현재 페이지를 업데이트:

  • 예: ?page=3
const { updateQueryString } = useQueryString();

const goToPage = (page: number) => {
  updateQueryString("page", page.toString());
};

 

3. 정렬 옵션 업데이트

사용자가 "가격순 정렬"이나 "인기순 정렬" 같은 옵션을 선택하면 URL에 반영:

  • 예: ?sort=price_asc
const { updateQueryString } = useQueryString();

const handleSortChange = (sortOption: string) => {
  updateQueryString("sort", sortOption);
};

 

4. 필터 초기화 및 상태 동기화

쿼리 파라미터를 이용해 컴포넌트 상태와 URL을 동기화하는 경우:

  • 예: 선택된 필터를 초기화하면서 URL도 갱신
const { updateQueryString } = useQueryString();

const resetFilters = () => {
  updateQueryString("category", "");
  updateQueryString("sort", "");
};

 

5. SPA(Single Page Application)에서 URL 상태 관리

Next.js와 같은 SPA 환경에서는 URL이 사용자 인터페이스의 일부처럼 동작합니다. 이런 경우 쿼리 문자열을 통해 상태를 유지하고 공유할 수 있습니다:

  • 예: 대시보드에서 특정 데이터를 표시하기 위해 ?view=chart를 추가.
const { updateQueryString } = useQueryString();

const switchView = (view: string) => {
  updateQueryString("view", view);
};

 

 

6. 브라우저 히스토리 스택 관리

URL을 변경하면서도 브라우저 히스토리 스택에 추가하지 않으려는 경우:

  • 예: 데이터가 업데이트될 때 사용자가 이전 URL로 돌아가는 동작을 방지.
const { updateQueryString } = useQueryString();

const updateWithoutHistory = () => {
  updateQueryString("filter", "new", { replace: true });
};