Next.js Search Params 与服务端过滤
Next.js App Router 可把搜索、筛选和排序条件放进 URL searchParams,由 Server Component 读取并驱动服务端查询,使状态可分享、可刷新、可前进后退。
[!info] related notes
- 所属 MOC: nextjs-moc
- 前置概念: nextjs-server-component-data-fetching、nextjs-file-system-routing
- 并列概念:
- 易混淆概念:
- 关系笔记:
Next.js Search Params 与服务端过滤
一句话定义
在 Next.js App Router 中,适合分享、刷新、前进后退和服务端查询的筛选条件,可以建模为 URL query string;Server Component 读取 searchParams 后直接据此查询并渲染结果。
为什么这不是普通的 useState
如果筛选条件只放在客户端局部状态:
Component state
→ 只能当前页面实例知道
→ 刷新可能丢失
→ URL 不能表达当前视图
如果把它放进 URL:
/search?important=true&q=react
↓
searchParams
↓
Server Component
↓
query / service
↓
filtered result
URL 因此同时承担“视图身份”和“可分享状态”的角色。
核心机制
典型流程:
用户修改筛选条件
→ 更新 URL search params
→ App Router 导航
→ Server Component 收到新的 searchParams
→ 服务端重新执行对应查询
→ 返回新的 RSC / UI 结果
这与客户端 useState + array.filter() 的关键差异不在语法,而在 状态 owner 与查询位置。
最小例子
export default async function NotesPage({
searchParams,
}: {
searchParams: Promise<{ important?: string }>
}) {
const { important } = await searchParams
const notes = await getNotes({
important: important === 'true' ? true : undefined,
})
return <NoteList notes={notes} />
}
客户端交互只需要改变 URL;真正的数据过滤可以留在服务器。
什么时候适合放 URL
适合:
- 搜索词
- filter
- sort
- page / cursor 的可导航部分
- tab / view mode(当分享当前视图有价值)
通常不适合:
- 输入框尚未提交的每一个临时字符状态
- modal 内部动画状态
- hover / focus
- 纯组件内部暂态 UI
与 Client Component 过滤的关系
小数据集 + 纯展示切换 + 不需要 URL 身份
→ Client Component 本地过滤可以更简单
结果集大 / 依赖数据库 / 需要 deep link / 分享 / 刷新保持
→ URL searchParams + Server Component 查询更自然
两者不是“服务端一定更高级”,而是由状态生命周期和数据 owner 决定。
常见误解
searchParams 不是可信业务输入
URL 仍由用户控制,因此服务端必须对枚举、数字范围、排序字段等进行解析和白名单验证。
URL 是状态,不是授权证明
?userId=123 或 /notes?owner=123 不能证明当前用户有读取该资源的权限。授权仍必须依赖服务端身份和资源关系。
Server Component filtering 不等于所有筛选都应该打数据库
极小、已经完整加载到浏览器的数据集,频繁交互过滤可能更适合客户端完成。
课程位置
对应 Full Stack Open Part 14 / Next.js 的 Search,以及“Showing important notes only, server component solution”。它建立在 Next.js Server Component 数据获取、Next.js 文件系统路由 与 URL state 思维之上。