04. Search Params:URL 是状态,不是字符串垃圾桶

这是 TanStack Router 最值得 Next.js 工程师认真看的部分。复杂筛选、表格、排序、分页、分享链接——都在这里。

传统 URLSearchParams 的问题

TanStack 的模型

TanStack Router 使用 JSON-first search params:第一层仍兼容 URLSearchParams,但 number、boolean、array、object 可以被解析/序列化,并通过 validateSearch 形成可信类型。

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

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

function ProductsPage() {
  const search = Route.useSearch()
  // search.page: number
  // search.sort: 'newest' | 'oldest' | 'price'
  // search.tags: string[]
}

写入 search params

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

Next.js 对照

Next 常见做法TanStack 做法后果
useSearchParams() 读字符串validateSearch 输出 typed object组件不用重复 parse
router.push('/x?page=2')Link search={{ page: 2 }}导航参数类型可检查
URL 状态和 data fetching 手动同步loaderDeps 声明依赖缓存 key 更明确
经验规则:刷新、分享、浏览器后退后仍应存在的 UI 状态,优先考虑 URL。临时 hover、modal open、未提交输入,不要污染 URL。URL 是状态管理器,不是心理垃圾桶。
快速判断

一个产品列表的 page/sort/tags 是否适合放在 search params?