useSearchParams
主要功能是让你在客户端组件中,读取和操作当前 URL 的查询参数,也就是 URL 中 ? 后面的部分。
🎯 核心功能:读取查询参数
想象一下,你的 URL 是这样的
https://example.com/search?keyword=nextjs&page=2&sort=popular
useSearchParams 就是一个专门用来获取 keyword=nextjs&page=2&sort=popular 这部分数据的工具。
1. 基本用法
useSearchParams 只能在 客户端组件 中使用。使用 "use client"; 指令来声明一个组件为客户端组件。
2. 常用 URLSearchParams API 方法
useSearchParams 返回的对象提供了以下常用方法:
| 方法 | 描述 | 示例 |
|---|---|---|
get(name) | 获取第一个匹配的参数值。如果不存在,返回 null。 | searchParams.get('page') |
getAll(name) | 获取所有匹配的参数值(返回数组)。 | searchParams.getAll('tag') |
has(name) | 检查某个参数是否存在(返回 true/false)。 | searchParams.has('sort') |
toString() | 将所有参数序列化回字符串。 | searchParams.toString() |
forEach() | 遍历所有参数。 | searchParams.forEach((value, key) => ...) |
useRouter
主要功能是让你在客户端组件中,通过代码来控制页面的跳转、刷新、返回等操作,而不是依赖用户点击 <a> 标签。
1. 基本用法
和 useSearchParams 一样,useRouter 也只能在客户端组件中使用。
📚 router 对象的常用方法
useRouter() 返回的 router 对象提供了以下核心方法:
| 方法 | 描述 | 示例 |
|---|---|---|
push(path) | 最常用。将新 URL 添加到浏览器历史记录栈,并导航到该页面。 | router.push('/about') |
replace(path) | 导航到新 URL,但不会在历史记录栈中添加新条目,而是替换当前条目。 | router.replace('/login') |
back() | 导航到历史记录中的上一个页面。 | router.back() |
forward() | 导航到历史记录中的下一个页面。 | router.forward() |
refresh() | 重新获取当前页面的数据并重新渲染,但不会改变 URL。类似于刷新页面,但更快。 | router.refresh() |
prefetch(path) | 预加载指定路径的页面。当用户可能要访问该页面时,可以提前加载,提升用户体验。 | router.prefetch('/dashboard') |
2. push vs replace 的区别
这是一个关键区别,直接影响用户体验。
-
router.push('/login'):- 用户在
/home页面点击登录。 - URL 变为
/login。 - 浏览器历史记录栈:
/home->/login。 - 用户点击浏览器的“返回”按钮,会回到
/home页面。
- 用户在
-
router.replace('/login'):- 用户在
/home页面点击登录。 - URL 变为
/login。 - 浏览器历史记录栈:
/login(/home被替换了)。 - 用户点击浏览器的“返回”按钮,会回到
/home之前的页面,而不是/home。
- 用户在
使用场景:
push:用于正常的页面跳转,用户可能需要返回。replace:用于重定向场景。例如,未登录用户访问受保护的页面/dashboard,你用replace将其跳转到/login,这样用户登录后就不应该再“返回”到需要登录的/dashboard页面了。
3. router.refresh() 的强大之处
router.refresh() 是 App Router 中一个非常有用的方法。它不会丢失客户端状态(如表单输入、滚动位置),但会向服务器发起一次请求,重新获取数据并重新渲染服务组件。
🚀 实战场景:结合 useRouter 更新查询参数
这是一个非常常见的组合:读取当前参数,然后根据用户操作更新 URL。
场景:一个分页组件,点击页码时更新 page 参数。
代码解析:
// app/components/Pagination.jsx
"use client";
import { useRouter, useSearchParams, usePathname } from 'next/navigation';
export default function Pagination({ totalPages }) {
const router = useRouter();
const pathname = usePathname(); // 获取当前路径,如 '/search'
const searchParams = useSearchParams();
const currentPage = Number(searchParams.get('page')) || 1;
const createPageURL = (pageNumber) => {
const params = new URLSearchParams(searchParams); // 复制当前所有参数
params.set('page', pageNumber.toString()); // 更新 page 参数
return `${pathname}?${params.toString()}`; // 构建新 URL
};
return (
<div>
{/* 上一页 */}
<button
onClick={() => router.push(createPageURL(currentPage - 1))}
disabled={currentPage <= 1}
>
上一页
</button>
<span> 第 {currentPage} 页 </span>
{/* 下一页 */}
<button
onClick={() => router.push(createPageURL(currentPage + 1))}
disabled={currentPage >= totalPages}
>
下一页
</button>
</div>
);
}
usePathname()获取当前路径部分(不含查询参数)。new URLSearchParams(searchParams)创建一个参数对象的副本,这样我们修改它时不会影响原始对象。params.set('page', ...)更新页码。router.push()导航到新构建的 URL,页面会自动刷新并显示新数据。
📌 总结
| Hook | 主要功能 | 典型场景 |
|---|---|---|
useRouter | 改变 URL,执行导航操作。 | 按钮点击跳转、登录后重定向、刷新数据。 |
useSearchParams | 读取 URL 的查询参数。 | 获取搜索关键词、筛选条件、页码。 |
usePathname | 读取 URL 的路径部分。 | 构建新 URL 时保留当前路径。 |