Next.js 路由跳转三者对比API场景Link href...默认首选声明式站内链接redirect(/path)Server Component / Server Action 里服务端直接跳转useRouter().push()客户端逻辑触发如表单提交成功后、定时跳转、按钮回调1. 声明式跳转最常用用Link组件适合菜单、按钮、列表项等可点击链接。基本用法import Link from next/link; Link href/about关于我们/Link;带动态路由参数对应文件app/posts/[slug]/page.tsxApp Router 动态段直接写进路径字符串const slug hello-world Link href{/posts/${slug}}文章详情/Link Link href{/tags/${tagName}}标签页/Link带查询参数Query String// 字符串写法最直观 Link href/search?qnextjspage2搜索 Next.js/Link // URLSearchParams参数多、需编码时更安全 const params new URLSearchParams({ q: nextjs, page: 2 }) Link href{/search?${params.toString()}}搜索 Next.js/Link // 对象写法仅固定 pathname query不含 [slug] 动态段 Link href{{ pathname: /search, query: { q: nextjs, page: 2 } }} 搜索 Next.js /Link特点客户端路由不整页刷新会预取prefetch目标页面体验更好SEO 友好本质是a2. 编程式跳转代码里跳转在事件处理、登录成功后、表单提交后等场景使用。基本用法use client; import { useRouter } from next/navigation; const router useRouter(); router.push(/dashboard); // 跳转可回退 router.replace(/login); // 替换当前历史记录不能回退到上一页 router.back(); // 返回 router.forward(); // 前进 router.refresh(); // 仅 App RouterURL 不变、不整页刷新但让当前路由的 Server Component 重新跑一遍拿到最新服务端数据。和 push / 浏览器刷新的区别操作URL 变吗整页刷新吗服务端组件重跑吗router.push(‘/other’)✅ 变❌客户端路由✅ 新页面router.refresh()❌ 不变❌✅ 当前页浏览器 F5❌ 不变✅ 整页重载✅ 且客户端状态全丢典型场景use client async function handleSubmit() { await updateProfile(formData) // 后端数据已更新 router.refresh() // 当前页重新拉服务端数据UI 更新 // 不需要 router.push(/profile)因为本来就在 profile 页 }带动态路由参数App Router 的router.push只接受字符串const slug hello-world; router.push(/posts/${slug}); router.replace(/tags/${tagName});带查询参数// 字符串写法 router.push(/search?qnextjspage2); // URLSearchParams const params new URLSearchParams({ q: nextjs, page: 2, sort: date }); router.push(/search?${params.toString()}); // 在当前页追加/修改 query保留其他参数需配合 usePathname / useSearchParams import { usePathname, useSearchParams } from next/navigation; const pathname usePathname(); const searchParams useSearchParams(); const next new URLSearchParams(searchParams.toString()); next.set(page, 3); router.push(${pathname}?${next.toString()});常见方法方法作用push跳转到新页面保留历史replace跳转并替换当前页不能回退到上一页back/forward浏览器历史前进后退refresh仅 App Router重新获取服务端数据3. 服务端跳转不经过客户端 JS适合权限校验、旧 URL 重定向、国际化路由等。基本用法import { redirect } from next/navigation; // Server Component / Server Action 中 redirect(/login);带参数跳转// 动态路由 redirect(/posts/${slug}); // 查询参数 redirect(/search?q${encodeURIComponent(keyword)}page1);其他方式middleware.ts里做条件重定向notFound()跳转到 404 页严格说是「展示 404」不是普通跳转调用 notFound() 时URL 不会变成 /404地址栏仍是 /posts/404-testNext.js 内部抛一个特殊的 NOT_FOUND 信号渲染最近一层的 not-found.tsx同类约定error.tsx、loading.tsx也是按路由段就近渲染且 URL 不变但触发方式不同——前者是运行时错误后者是 Suspense 加载。4. 跳转后如何获取参数跳转时传的参数分两类动态路由段/posts/[slug]和查询参数?qxxx。服务端Server Component页面组件通过 props 接收// app/posts/[slug]/page.tsx interface Props { params: Promise{ slug: string }; searchParams: Promise{ q?: string; page?: string }; } export default async function Page({ params, searchParams }: Props) { const { slug } await params; // 动态段/posts/hello → slug hello const { q, page } await searchParams; // 查询串?qnextjspage2 // ... }Server Action 里可从formData或函数参数读取再redirect到带参 URL。客户端Client Componentuse client; import { useParams, useSearchParams } from next/navigation; export default function SearchBar() { const params useParams(); // { slug: hello } const searchParams useSearchParams(); const slug params.slug as string; const q searchParams.get(q); // nextjs 或 null const page searchParams.get(page) ?? 1; // ... }useSearchParams()会使组件在客户端渲染若只需在服务端读 query优先用 Server Component 的searchParamsprop。参数类型对照参数来源URL 示例跳转写法读取方式服务端读取方式客户端动态路由段/posts/hello/posts/${slug}(await params).sluguseParams().slug查询参数/search?qnextjs/search?${params}或URLSearchParams(await searchParams).quseSearchParams().get(q)多段动态路由/tags/react/tags/${name}(await params).sluguseParams().slug速记能点链接就用LinkSEO 和预取都更好。事件里跳转用router.push/replace记得use client。权限/校验在服务端用redirect不暴露客户端逻辑。动态段用params查询串用searchParams客户端对应useParams/useSearchParams。
Next.js - 03 - 路由详解
Next.js 路由跳转三者对比API场景Link href...默认首选声明式站内链接redirect(/path)Server Component / Server Action 里服务端直接跳转useRouter().push()客户端逻辑触发如表单提交成功后、定时跳转、按钮回调1. 声明式跳转最常用用Link组件适合菜单、按钮、列表项等可点击链接。基本用法import Link from next/link; Link href/about关于我们/Link;带动态路由参数对应文件app/posts/[slug]/page.tsxApp Router 动态段直接写进路径字符串const slug hello-world Link href{/posts/${slug}}文章详情/Link Link href{/tags/${tagName}}标签页/Link带查询参数Query String// 字符串写法最直观 Link href/search?qnextjspage2搜索 Next.js/Link // URLSearchParams参数多、需编码时更安全 const params new URLSearchParams({ q: nextjs, page: 2 }) Link href{/search?${params.toString()}}搜索 Next.js/Link // 对象写法仅固定 pathname query不含 [slug] 动态段 Link href{{ pathname: /search, query: { q: nextjs, page: 2 } }} 搜索 Next.js /Link特点客户端路由不整页刷新会预取prefetch目标页面体验更好SEO 友好本质是a2. 编程式跳转代码里跳转在事件处理、登录成功后、表单提交后等场景使用。基本用法use client; import { useRouter } from next/navigation; const router useRouter(); router.push(/dashboard); // 跳转可回退 router.replace(/login); // 替换当前历史记录不能回退到上一页 router.back(); // 返回 router.forward(); // 前进 router.refresh(); // 仅 App RouterURL 不变、不整页刷新但让当前路由的 Server Component 重新跑一遍拿到最新服务端数据。和 push / 浏览器刷新的区别操作URL 变吗整页刷新吗服务端组件重跑吗router.push(‘/other’)✅ 变❌客户端路由✅ 新页面router.refresh()❌ 不变❌✅ 当前页浏览器 F5❌ 不变✅ 整页重载✅ 且客户端状态全丢典型场景use client async function handleSubmit() { await updateProfile(formData) // 后端数据已更新 router.refresh() // 当前页重新拉服务端数据UI 更新 // 不需要 router.push(/profile)因为本来就在 profile 页 }带动态路由参数App Router 的router.push只接受字符串const slug hello-world; router.push(/posts/${slug}); router.replace(/tags/${tagName});带查询参数// 字符串写法 router.push(/search?qnextjspage2); // URLSearchParams const params new URLSearchParams({ q: nextjs, page: 2, sort: date }); router.push(/search?${params.toString()}); // 在当前页追加/修改 query保留其他参数需配合 usePathname / useSearchParams import { usePathname, useSearchParams } from next/navigation; const pathname usePathname(); const searchParams useSearchParams(); const next new URLSearchParams(searchParams.toString()); next.set(page, 3); router.push(${pathname}?${next.toString()});常见方法方法作用push跳转到新页面保留历史replace跳转并替换当前页不能回退到上一页back/forward浏览器历史前进后退refresh仅 App Router重新获取服务端数据3. 服务端跳转不经过客户端 JS适合权限校验、旧 URL 重定向、国际化路由等。基本用法import { redirect } from next/navigation; // Server Component / Server Action 中 redirect(/login);带参数跳转// 动态路由 redirect(/posts/${slug}); // 查询参数 redirect(/search?q${encodeURIComponent(keyword)}page1);其他方式middleware.ts里做条件重定向notFound()跳转到 404 页严格说是「展示 404」不是普通跳转调用 notFound() 时URL 不会变成 /404地址栏仍是 /posts/404-testNext.js 内部抛一个特殊的 NOT_FOUND 信号渲染最近一层的 not-found.tsx同类约定error.tsx、loading.tsx也是按路由段就近渲染且 URL 不变但触发方式不同——前者是运行时错误后者是 Suspense 加载。4. 跳转后如何获取参数跳转时传的参数分两类动态路由段/posts/[slug]和查询参数?qxxx。服务端Server Component页面组件通过 props 接收// app/posts/[slug]/page.tsx interface Props { params: Promise{ slug: string }; searchParams: Promise{ q?: string; page?: string }; } export default async function Page({ params, searchParams }: Props) { const { slug } await params; // 动态段/posts/hello → slug hello const { q, page } await searchParams; // 查询串?qnextjspage2 // ... }Server Action 里可从formData或函数参数读取再redirect到带参 URL。客户端Client Componentuse client; import { useParams, useSearchParams } from next/navigation; export default function SearchBar() { const params useParams(); // { slug: hello } const searchParams useSearchParams(); const slug params.slug as string; const q searchParams.get(q); // nextjs 或 null const page searchParams.get(page) ?? 1; // ... }useSearchParams()会使组件在客户端渲染若只需在服务端读 query优先用 Server Component 的searchParamsprop。参数类型对照参数来源URL 示例跳转写法读取方式服务端读取方式客户端动态路由段/posts/hello/posts/${slug}(await params).sluguseParams().slug查询参数/search?qnextjs/search?${params}或URLSearchParams(await searchParams).quseSearchParams().get(q)多段动态路由/tags/react/tags/${name}(await params).sluguseParams().slug速记能点链接就用LinkSEO 和预取都更好。事件里跳转用router.push/replace记得use client。权限/校验在服务端用redirect不暴露客户端逻辑。动态段用params查询串用searchParams客户端对应useParams/useSearchParams。