Menu

useSearchParams

useSearchParams 是一个 Client Component hook,它允许你读取当前 URL 的查询字符串

useSearchParams 返回 URLSearchParams 接口的只读版本。

app/dashboard/search-bar.tsx
TypeScript
'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 不接受任何参数。

返回值

useSearchParams 返回 URLSearchParams 接口的只读版本,其中包含用于读取 URL 查询字符串的实用方法:

值得注意的是

  • useSearchParams 是一个 Client Component hook,在 Server Components不受支持,以防止在部分渲染期间出现过期值。
  • 如果你想在 Server Component 中基于搜索参数获取数据,通常更好的选择是读取相应 Page 的 searchParams prop。然后你可以通过 props 将其传递给该 Page 中的任何组件(Server 或 Client)。
  • 如果应用程序包含 /pages 目录,useSearchParams 将返回 ReadonlyURLSearchParams | nullnull 值是为了迁移期间的兼容性,因为在不使用 getServerSideProps 的页面预渲染期间无法知道搜索参数

行为

静态渲染

如果路由是静态渲染的,调用 useSearchParams 将导致 Client Component 树直到最近的 Suspense 边界在客户端渲染。

这允许路由的一部分被静态渲染,而使用 useSearchParams 的动态部分在客户端渲染。

我们建议将使用 useSearchParams 的 Client Component 包装在 <Suspense/> 边界中。这将允许其上方的任何 Client Components 被静态渲染并作为初始 HTML 的一部分发送。示例

例如:

app/dashboard/search-bar.tsx
TypeScript
'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
TypeScript
import { Suspense } from 'react'
import SearchBar from './search-bar'
 
// 这个作为 Suspense 边界的 fallback 传递的组件
// 将在初始 HTML 中代替搜索栏进行渲染。
// 当 React hydration 期间值可用时,fallback
// 将被 `<SearchBar>` 组件替换。
function SearchBarFallback() {
  return <>placeholder</>
}
 
export default function Page() {
  return (
    <>
      <nav>
        <Suspense fallback={<SearchBarFallback />}>
          <SearchBar />
        </Suspense>
      </nav>
      <h1>Dashboard</h1>
    </>
  )
}

值得注意的是

  • 在开发环境中,路由是按需渲染的,因此 useSearchParams 不会挂起,没有 Suspense 的情况下可能看起来正常工作。
  • 在生产构建期间,从 Client Component 调用 useSearchParams静态页面必须包装在 Suspense 边界中,否则构建将失败并出现 Missing Suspense boundary with useSearchParams 错误。
  • 如果你希望路由被动态渲染,优先在 Server Component 中首先使用 connection 函数来等待传入的请求,这将排除下面的所有内容进行预渲染。查看动态渲染指南中使路由动态化的因素。
  • 如果你已经在 Server Component Page 中,考虑使用 searchParams prop 并将值传递给 Client Components。
  • 你也可以将 Page searchParams prop 直接传递给 Client Component,并使用 React 的 use() 解包它。虽然这会挂起,所以 Client Component 应该用 Suspense 边界包装。

动态渲染

如果路由是动态渲染的,useSearchParams 将在 Client Component 的初始服务器渲染期间在服务器上可用。

例如:

app/dashboard/search-bar.tsx
TypeScript
'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
TypeScript
import { connection } from 'next/server'
import SearchBar from './search-bar'
 
export default async function Page() {
  await connection()
  return (
    <>
      <nav>
        <SearchBar />
      </nav>
      <h1>Dashboard</h1>
    </>
  )
}

值得注意的是

  • 以前,在页面上设置 export const dynamic = 'force-dynamic' 用于强制动态渲染。优先使用 connection(),因为它在语义上将动态渲染与传入请求绑定。

Server Components

Pages

要在 Pages(Server Components)中访问搜索参数,请使用 searchParams prop。

Layouts

与 Pages 不同,Layouts(Server Components)不会接收 searchParams prop。这是因为共享布局在导航期间不会重新渲染,这可能导致导航之间的 searchParams 过期。查看详细解释

相反,使用 Page searchParams prop 或在 Client Component 中使用 useSearchParams hook,它会在客户端使用最新的 searchParams 重新渲染。

示例

更新 searchParams

你可以使用 useRouterLink 来设置新的 searchParams。执行导航后,当前的 page.js 将收到更新的 searchParams prop

app/example-client-component.tsx
TypeScript
'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>Sort By</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>
    </>
  )
}

版本历史

VersionChanges
v13.0.0引入 useSearchParams