SuperAPI AI 工具集

router-core/search-params

前端与建站

查看项目

更新于 10-16 10:01

技能介绍

用途

TanStack Router 将搜索参数(Search Params)视为 JSON 优先的应用状态。它们会自动从 URL 解析为结构化对象(数字、布尔值、数组、嵌套对象),并在每个路由上通过 validateSearch 进行验证。

主要能力

参数验证

支持通过 Zod、Valibot、ArkType 适配器进行搜索参数验证。

使用 Zod 适配器(推荐)时,需要安装:

npm install zod @tanstack/zod-adapter

示例 schema:

import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'

const productSearchSchema = z.object({
  page: z.number().default(1).catch(1),
  filter: z.string().default(''),
  sort: z.enum(['newest', 'oldest', 'price']).default('newest').catch('newest'),
})

export const Route = createFileRoute('/products')({
  validateSearch: productSearchSchema,
  component: ProductsPage,
})

注意:使用 zodValidator() 与 Zod v3 时,应使用 @tanstack/zod-adapter 的 fallback(),而不是 zod 的 .catch()。使用 .catch() 配合 zod 适配器会让输出类型变为 unknown,破坏类型安全。这不适用于 Valibot 或 ArkType(它们使用各自的回退机制),也不适用于 Zod v4(v4 应使用 .catch(),而不是 zodValidator())。类型可完全推断,不要为 useSearch() 的返回值添加类型标注。

读取搜索参数

路由组件中:Route.useSearch()

function ProductsPage() {
  const { page, sort } = Route.useSearch()
  return <div>Page {page}</div>
}

代码分割组件中:getRouteApi()

import { getRouteApi } from '@tanstack/react-router'
const routeApi = getRouteApi('/products')

function ProductFilters() {
  const { sort } = routeApi.useSearch()
  return <select value={sort}>{/* options */}</select>
}

任意组件中:useSearch({ from })

import { useSearch } from '@tanstack/react-router'

function SortIndicator() {
  const { sort } = useSearch({ from: '/products' })
  return <span>Sorted by: {sort}</span>
}

宽松访问:useSearch({ strict: false })

function GenericPaginator() {
  const search = useSearch({ strict: false })
  return <span>Page: {search.page ?? 1}</span>
}

写入搜索参数

Link 函数形式(保留已有参数):

<Link from="/products" search={(prev) => ({ ...prev, page: prev.page + 1 })}>
  Next Page
</Link>

Link 对象形式(替换所有参数):

<Link to="/products" search={{ page: 1, filter: '', sort: 'newest' }}>
  Reset
</Link>

编程式:useNavigate()

const navigate = useNavigate({ from: '/products' })
navigate({
  search: (prev) => ({ ...prev, sort: e.target.value, page: 1 }),
})

搜索参数继承

父路由的搜索参数会自动合并到子路由。父路由必须定义 validateSearch,子路由才能继承。

搜索中间件

retainSearchParams:跨导航保留参数。

search: {
  middlewares: [retainSearchParams(['debug'])],
}

stripSearchParams:从 URL 中移除默认值。

search: {
  middlewares: [stripSearchParams(defaults)],
}

中间件可以链式组合:

search: {
  middlewares: [
    retainSearchParams(['retainMe']),
    stripSearchParams({ arrayWithDefaults: ['foo', 'bar'] }),
  ],
}

自定义序列化

可在路由器级别覆盖默认的 JSON 序列化:

import {
  createRouter,
  parseSearchWith,
  stringifySearchWith,
} from '@tanstack/react-router'

const router = createRouter({
  routeTree,
  parseSearch: parseSearchWith(parse),
  stringifySearch: stringifySearchWith(stringify),
})

通过 loaderDeps 在 loader 中使用

export const Route = createFileRoute('/products')({
  validateSearch: productSearchSchema,
  loaderDeps: ({ search }) => ({ page: search.page }),
  loader: async ({ deps }) => {
    return fetchProducts({ page: deps.page })
  },
})

常见错误

  1. 在 Zod v3 中将 .catch() 与 zodValidator() 一起使用,而非适配器的 fallback()。正确做法是导入 fallback 并使用 fallback(z.number(), 1)。此问题仅适用于 Zod v3。

  2. 从 loaderDeps 返回整个搜索对象 —— 会导致任何搜索参数变化都触发 loader 重新运行。应只挑选 loader 需要的参数。

  3. 在搜索参数中传递 Date 对象 —— Date 无法正确序列化为 URL 中的 JSON。应转换为 ISO 字符串:new Date().toISOString()。

  4. 父路由缺少 validateSearch 会阻止继承。

  5. 将 search 用作对象而非函数会丢失参数 —— 应使用函数形式 search={(prev) => ({ ...prev, page: 2 })} 保留现有参数。

适用场景与限制

适用于使用 TanStack Router 的 React 应用,需要在 URL 中管理结构化、类型安全的搜索参数状态,并执行验证、默认值处理、参数保留或清理。限制与更多模式信息暂未提供。