---
id: url-state
track: learn
product: router
locale: zh-CN
order: 4
revision: 2
sourceCheckedOn: "2026-08-03"
versionRange: "Router ^1"
verifiedAgainst: "@tanstack/react-router@1.170.18"
contentModel: 2
prerequisites:
  - "理解文件路由"
sourceRefs:
  - "https://tanstack.com/router/latest/docs/guide/search-params"
---

# 把筛选条件放进 URL

> 用经过验证的 Search Params 实现可分享、可刷新、有类型的 Issue 筛选。

**Outcome:** 能判断哪些状态应放 URL，并为它们提供稳定默认值。

## 搜索参数是外部输入

用户可以手动改 URL，老书签也可能带着过期数据。所以不要在组件里临时 Number()，而要在路由边界集中验证。

File: `src/routes/issues/index.tsx`

```tsx
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/issues/')({
  validateSearch: (search: Record<string, unknown>) => ({
    page: Math.max(1, Number(search.page) || 1),
    status: search.status === 'closed' ? 'closed' : 'open',
  }),
  component: IssuesPage,
})

function IssuesPage() {
  const filters = Route.useSearch()
  return <p>Page {filters.page} · {filters.status}</p>
}
```

## 什么状态应该放 URL

能被分享、书签化、前进后退或刷新恢复的状态，例如筛选、排序、分页和当前标签，通常适合 URL。按钮是否正在 hover 这类瞬时状态不适合。

## 实践与验证

### 完成检查点

筛选、状态和页码都可从 URL 恢复，刷新或分享链接不会丢失视图。

### 动手练习

增加一个带默认值的 priority 筛选，并保证写入 URL 时省略默认值。

### 验证方法

打开含非法页码的 URL 应回退到安全值；复制有效 URL 到新标签页应得到同一筛选结果。

### 常见错误

- 只做 TypeScript 断言而不做运行时验证。
- 在更新一个筛选项时意外清空其他 search 参数。

## Official sources

- https://tanstack.com/router/latest/docs/guide/search-params
