문서
App Router 사용하기
useSearchParams

useSearchParams

useSearchParams는 현재 URL의 쿼리 문자열을 읽을 수 있게 해주는 클라이언트 컴포넌트 훅입니다.

useSearchParamsURLSearchParams 인터페이스의 읽기 전용 버전을 반환합니다.

app/dashboard/search-bar.tsx
"use client";
 
import { useSearchParams } from "next/navigation";
 
export default function SearchBar() {
  const searchParams = useSearchParams();
 
  const search = searchParams.get("search");
 
  // URL -> `/dashboard?search=my-project`
  // `search` -> 'my-project'
  return <>Search: {search}</>;
}
app/dashboard/search-bar.js
"use client";
 
import { useSearchParams } from "next/navigation";
 
export default function SearchBar() {
  const searchParams = useSearchParams();
 
  const search = searchParams.get("search");
 
  // URL -> `/dashboard?search=my-project`
  // `search` -> 'my-project'
  return <>Search: {search}</>;
}

매개변수

const searchParams = useSearchParams();

useSearchParams는 매개변수를 받지 않습니다.

반환값

useSearchParamsURLSearchParams 인터페이스의 읽기 전용 버전을 반환하며, 여기에는 URL의 쿼리 문자열을 읽기 위한 유틸리티 메서드가 포함되어 있습니다:

  • URLSearchParams.get(): 검색 매개변수와 관련된 첫 번째 값을 반환합니다. 예를 들어:

    URLsearchParams.get("a")
    /dashboard?a=1'1'
    /dashboard?a=''
    /dashboard?b=3null
    /dashboard?a=1&a=2'1' - 모든 값을 가져오려면 getAll() 사용
  • URLSearchParams.has(): 주어진 매개변수가 존재하는지 여부를 나타내는 불리언 값을 반환합니다. 예를 들어:

    URLsearchParams.has("a")
    /dashboard?a=1true
    /dashboard?b=3false
  • URLSearchParams의 다른 읽기 전용 메서드에 대해 자세히 알아보세요. 여기에는 getAll(), keys(), values(), entries(), forEach(), toString()이 포함됩니다.

알아두면 좋은 점:

  • useSearchParams클라이언트 컴포넌트 훅이며 서버 컴포넌트에서는 지원되지 않습니다. 이는 부분 렌더링 중 오래된 값을 방지하기 위함입니다.
  • 애플리케이션에 /pages 디렉토리가 포함되어 있다면, useSearchParamsReadonlyURLSearchParams | null을 반환합니다. null 값은 마이그레이션 중 호환성을 위한 것으로, getServerSideProps를 사용하지 않는 페이지의 사전 렌더링 중에는 검색 매개변수를 알 수 없기 때문입니다.

정적 렌더링

경로가 정적으로 렌더링되는 경우, useSearchParams를 호출하면 가장 가까운 Suspense 경계까지의 클라이언트 컴포넌트 트리가 클라이언트 측에서 렌더링됩니다.

이를 통해 경로의 일부를 정적으로 렌더링하면서 useSearchParams를 사용하는 동적 부분은 클라이언트 측에서 렌더링할 수 있습니다.

useSearchParams를 사용하는 클라이언트 컴포넌트를 <Suspense/> 경계로 감싸는 것을 권장합니다. 이렇게 하면 그 위의 클라이언트 컴포넌트들을 정적으로 렌더링하여 초기 HTML의 일부로 보낼 수 있습니다. 예시를 참조하세요.

예를 들어:

app/dashboard/search-bar.tsx
"use client";
 
import { useSearchParams } from "next/navigation";
 
export default function SearchBar() {
  const searchParams = useSearchParams();
 
  const search = searchParams.get("search");
 
  // 정적 렌더링을 사용할 때 이 로그는 서버에서 기록되지 않습니다
  console.log(search);
 
  return <>Search: {search}</>;
}
app/dashboard/search-bar.js
"use client";
 
import { useSearchParams } from "next/navigation";
 
export default function SearchBar() {
  const searchParams = useSearchParams();
 
  const search = searchParams.get("search");
 
  // 정적 렌더링을 사용할 때 이 로그는 서버에서 기록되지 않습니다
  console.log(search);
 
  return <>Search: {search}</>;
}
app/dashboard/page.tsx
import { Suspense } from "react";
import SearchBar from "./search-bar";
 
// Suspense 경계에 대한 폴백으로 전달되는 이 컴포넌트는
// 초기 HTML에서 검색 바 대신 렌더링됩니다.
// React 하이드레이션 중에 값을 사용할 수 있게 되면
// 폴백은 `<SearchBar>` 컴포넌트로 대체됩니다.
function SearchBarFallback() {
  return <>placeholder</>;
}
 
export default function Page() {
  return (
    <>
      <nav>
        <Suspense fallback={<SearchBarFallback />}>
          <SearchBar />
        </Suspense>
      </nav>
      <h1>Dashboard</h1>
    </>
  );
}
app/dashboard/page.js
import { Suspense } from "react";
import SearchBar from "./search-bar";
 
// Suspense 경계에 대한 폴백으로 전달되는 이 컴포넌트는
// 초기 HTML에서 검색 바 대신 렌더링됩니다.
// React 하이드레이션 중에 값을 사용할 수 있게 되면
// 폴백은 `<SearchBar>` 컴포넌트로 대체됩니다.
function SearchBarFallback() {
  return <>placeholder</>;
}
 
export default function Page() {
  return (
    <>
      <nav>
        <Suspense fallback={<SearchBarFallback />}>
          <SearchBar />
        </Suspense>
      </nav>
      <h1>Dashboard</h1>
    </>
  );
}

동작

동적 렌더링

경로가 동적으로 렌더링되는 경우, useSearchParams는 클라이언트 컴포넌트의 초기 서버 렌더링 중에 서버에서 사용할 수 있습니다.

예를 들어:

app/dashboard/search-bar.tsx
"use client";
 
import { useSearchParams } from "next/navigation";
 
export default function SearchBar() {
  const searchParams = useSearchParams();
 
  const search = searchParams.get("search");
 
  // 이는 초기 렌더링 중에 서버에서 기록되고
  // 이후 탐색에서는 클라이언트에서 기록됩니다.
  console.log(search);
 
  return <>Search: {search}</>;
}
app/dashboard/search-bar.js
"use client";
 
import { useSearchParams } from "next/navigation";
 
export default function SearchBar() {
  const searchParams = useSearchParams();
 
  const search = searchParams.get("search");
 
  // 이는 초기 렌더링 중에 서버에서 기록되고
  // 이후 탐색에서는 클라이언트에서 기록됩니다.
  console.log(search);
 
  return <>Search: {search}</>;
}
app/dashboard/page.tsx
import SearchBar from "./search-bar";
 
export const dynamic = "force-dynamic";
 
export default function Page() {
  return (
    <>
      <nav>
        <SearchBar />
      </nav>
      <h1>Dashboard</h1>
    </>
  );
}
app/dashboard/page.js
import SearchBar from "./search-bar";
 
export const dynamic = "force-dynamic";
 
export default function Page() {
  return (
    <>
      <nav>
        <SearchBar />
      </nav>
      <h1>Dashboard</h1>
    </>
  );
}

알아두면 좋은 점: dynamic 라우트 세그먼트 구성 옵션force-dynamic으로 설정하면 동적 렌더링을 강제할 수 있습니다.

서버 컴포넌트

페이지

페이지 (서버 컴포넌트)에서 검색 매개변수에 접근하려면 searchParams prop을 사용하세요.

레이아웃

페이지와 달리 레이아웃 (서버 컴포넌트)은 searchParams prop을 받지 않습니다. 이는 공유 레이아웃이 탐색 중에 다시 렌더링되지 않기 때문에 탐색 사이에 오래된 searchParams가 생길 수 있기 때문입니다. 자세한 설명을 참조하세요.

대신, 페이지 searchParams prop을 사용하거나 클라이언트 컴포넌트에서 useSearchParams 훅을 사용하세요. 이는 최신 searchParams로 클라이언트에서 다시 렌더링됩니다.

예시

searchParams 업데이트하기

useRouter 또는 Link를 사용하여 새로운 searchParams를 설정할 수 있습니다. 탐색이 수행된 후, 현재 page.js는 업데이트된 searchParams prop을 받게 됩니다.

app/example-client-component.tsx
"use client";
 
export default function ExampleClientComponent() {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
 
  // 현재 searchParams를 제공된 키/값 쌍과 병합하여
  // 새로운 searchParams 문자열을 얻습니다
  const createQueryString = useCallback(
    (name: string, value: string) => {
      const params = new URLSearchParams(searchParams.toString());
      params.set(name, value);
 
      return params.toString();
    },
    [searchParams]
  );
 
  return (
    <>
      <p>정렬 기준</p>
 
      {/* useRouter 사용 */}
      <button
        onClick={() => {
          // <pathname>?sort=asc
          router.push(pathname + "?" + createQueryString("sort", "asc"));
        }}
      >
        ASC
      </button>
 
      {/* <Link> 사용 */}
      <Link
        href={
          // <pathname>?sort=desc
          pathname + "?" + createQueryString("sort", "desc")
        }
      >
        DESC
      </Link>
    </>
  );
}
app/example-client-component.js
"use client";
 
export default function ExampleClientComponent() {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
 
  // 현재 searchParams를 제공된 키/값 쌍과 병합하여
  // 새로운 searchParams 문자열을 얻습니다
  const createQueryString = useCallback(
    (name, value) => {
      const params = new URLSearchParams(searchParams);
      params.set(name, value);
 
      return params.toString();
    },
    [searchParams]
  );
 
  return (
    <>
      <p>정렬 기준</p>
 
      {/* useRouter 사용 */}
      <button
        onClick={() => {
          // <pathname>?sort=asc
          router.push(pathname + "?" + createQueryString("sort", "asc"));
        }}
      >
        ASC
      </button>
 
      {/* <Link> 사용 */}
      <Link
        href={
          // <pathname>?sort=desc
          pathname + "?" + createQueryString("sort", "desc")
        }
      >
        DESC
      </Link>
    </>
  );
}

버전 기록

버전변경 사항
v13.0.0useSearchParams 도입됨.