路由导航
2026年9月6日
同站跳转不要用原生 <a href> 硬刷新。框架提供了预取、保滚动、替换历史这几件事,按场景选 API。
常用四条:
<Link>:声明式,菜单、列表最合适useRouter:点击、权限判断后在客户端命令式跳redirect/permanentRedirect:服务端(或 Server Action)里改去向- History API:极少用,知道即可
Link
next/link 在 <a> 上加了预取和客户端切换:
import Link from "next/link";
export default function Nav() {
return (
<nav>
<Link href="/about">关于</Link>
<Link href={{ pathname: "/about", query: { name: "槿" } }}>带查询</Link>
<Link href="/docs" prefetch>
预取
</Link>
<Link href="/long-page" scroll={false}>
不滚回顶部
</Link>
<Link href="/login" replace>
替换历史
</Link>
</nav>
);
}
tsx
列表里动态拼地址完全没问题:
{ids.map((id) => (
<Link key={id} href={`/posts/${id}`}>
文章 {id}
</Link>
))}
tsx
视口里的 Link 默认会预取目标页。关闭:prefetch={false}。replace 不会往历史栈再推一条,适合「登录成功盖掉登录页」。
useRouter
只能在客户端组件里用,从 next/navigation 引入(不要用旧的 next/router):
"use client";
import { useRouter } from "next/navigation";
export default function Toolbar() {
const router = useRouter();
return (
<>
<button onClick={() => router.push("/posts")}>去列表</button>
<button onClick={() => router.replace("/login")}>替换到登录</button>
<button onClick={() => router.back()}>后退</button>
<button onClick={() => router.forward()}>前进</button>
<button onClick={() => router.refresh()}>刷新服务端数据</button>
</>
);
}
tsx
refresh() 不会整页重载,而是重新跑当前路由的服务端组件。权限分支、表单成功后的跳转,用这套比一堆 Link 好写。
redirect
服务端组件或 Server Action 里改去向:
import { redirect } from "next/navigation";
export default async function Page() {
const user = await getSession();
if (!user) {
redirect("/login");
}
return <p>已登录</p>;
}
tsx
redirect 发出的是 307 临时重定向。它会抛出一个框架认识的特殊错误,后面的代码不会继续跑,这是预期行为。
permanentRedirect
用法相同,状态码是 308 永久重定向。URL 搬家、旧路径作废时用它,方便搜索引擎更新索引。
import { permanentRedirect } from "next/navigation";
export default function OldDocs() {
permanentRedirect("/docs/nextjs/01-getting-started");
}
tsx
两个函数都接收目标路径(相对或绝对)。在 Server Action / 客户端里还可以传 type: "push" | "replace" 控制历史栈;服务端组件里这个参数无效,一律按 replace 理解。
默认历史行为:
- Server Action:默认
push - 其他场景:默认
replace
怎么选
| 场景 | 用谁 |
|---|---|
| 导航、卡片、目录 | Link |
| 按钮、校验后再跳 | useRouter |
| 服务端发现没登录 / 数据不存在 | redirect |
| 路径永久作废 | permanentRedirect |
下一篇是动态段:[slug]、[...slug]、[[...slug]]。