链接与导航
在 Next.js 中有四种方式实现路由间的导航:
- 使用
<Link>
组件 - 使用
useRouter
钩子(客户端组件) - 使用
redirect
函数(服务端组件) - 使用原生 History API
本页将介绍如何使用这些选项,并深入探讨导航的工作原理。
<Link>
组件
<Link>
是一个内置组件,它扩展了 HTML <a>
标签的功能,提供预加载和客户端路由导航。这是 Next.js 中推荐的主要路由导航方式。
你可以从 next/link
导入它,并向组件传递 href
属性:
你还可以向 <Link>
传递其他可选属性。详见 API 参考文档。
useRouter()
钩子
useRouter
钩子允许你在客户端组件中以编程方式更改路由。
有关 useRouter
方法的完整列表,请参阅 API 参考文档。
推荐: 除非有特殊需求,否则应优先使用
<Link>
组件进行路由导航。
redirect
函数
对于服务端组件,请使用 redirect
函数。
须知:
redirect
默认返回 307(临时重定向)状态码。在服务器操作中使用时,它会返回 303(参见其他),通常用于在 POST 请求后重定向到成功页面。redirect
内部会抛出错误,因此应在try/catch
块之外调用。redirect
可以在客户端组件的渲染过程中调用,但不能在事件处理程序中调用。这种情况下应使用useRouter
钩子。redirect
也接受绝对 URL,可用于重定向到外部链接。- 如果需要在渲染过程之前重定向,请使用
next.config.js
或 中间件。
更多信息请参阅 redirect
API 参考文档。
使用原生 History API
Next.js 允许使用原生的 window.history.pushState
和 window.history.replaceState
方法来更新浏览器的历史记录栈而无需重新加载页面。
pushState
和 replaceState
调用会与 Next.js 路由器集成,使你可以与 usePathname
和 useSearchParams
同步。
window.history.pushState
用于向浏览器的历史记录栈添加新条目。用户可以导航回先前的状态。例如,对产品列表进行排序:
window.history.replaceState
用于替换浏览器历史记录栈中的当前条目。用户无法导航回先前的状态。例如,切换应用程序的语言环境:
路由与导航工作原理
应用路由器采用混合方法实现路由和导航。在服务器端,你的应用代码会根据路由段自动进行代码分割。在客户端,Next.js 会预加载并缓存路由段。这意味着当用户导航到新路由时,浏览器不会重新加载页面,只有发生变化的路由段会重新渲染——从而提升导航体验和性能。
1. 代码分割
代码分割允许你将应用代码拆分为更小的包,由浏览器下载和执行。这减少了每次请求传输的数据量和执行时间,从而提升性能。
服务端组件允许你的应用代码按路由段自动进行代码分割。这意味着导航时只加载当前路由所需的代码。
2. 预加载
预加载是一种在用户访问路由前在后台预先加载路由的方式。
Next.js 中有两种预加载路由的方式:
<Link>
组件:当路由出现在用户视口中时自动预加载。预加载发生在页面首次加载或通过滚动进入视图时。router.prefetch()
:可以使用useRouter
钩子以编程方式预加载路由。
<Link>
的默认预加载行为(即当 prefetch
属性未指定或设为 null
时)会根据 loading.js
的使用情况而有所不同。只有共享布局,直到第一个 loading.js
文件的渲染"树"会被预加载并缓存 30s
。这降低了获取整个动态路由的成本,意味着你可以显示即时加载状态以提供更好的视觉反馈。
你可以通过将 prefetch
属性设为 false
来禁用预加载。或者,也可以通过将 prefetch
属性设为 true
来预加载超出加载边界的完整页面数据。
更多信息请参阅 <Link>
API 参考文档。
须知:
- 预加载仅在生产环境中启用,开发环境中不启用。
3. 缓存
Next.js 有一个称为路由器缓存的内存客户端缓存。当用户在应用中导航时,预加载的路由段和已访问路由的 React 服务端组件负载会被存储在缓存中。
这意味着在导航时,会尽可能重用缓存,而不是向服务器发起新请求——通过减少请求次数和传输数据量来提升性能。
了解更多关于路由器缓存的工作原理及如何配置。
4. 部分渲染
部分渲染意味着在客户端导航时,只有发生变化的路由段会重新渲染,任何共享段都会被保留。
例如,当在两个同级路由 /dashboard/settings
和 /dashboard/analytics
之间导航时,settings
页面会被卸载,analytics
页面会以新状态挂载,而共享的 dashboard
布局会被保留。这种行为也存在于同一动态段上的两个路由之间,例如 /blog/[slug]/page
和从 /blog/first
导航到 /blog/second
。

如果没有部分渲染,每次导航都会导致客户端重新渲染整个页面。仅渲染发生变化的部分减少了传输的数据量和执行时间,从而提升性能。
5. 软导航
浏览器在页面间导航时会执行"硬导航"。Next.js 应用路由器实现了页面间的"软导航",确保只有发生变化的路由段会重新渲染(部分渲染)。这使得客户端 React 状态在导航过程中得以保留。
6. 前进和后退导航
默认情况下,Next.js 会为前进和后退导航保持滚动位置,并重用路由器缓存中的路由段。
7. pages/
和 app/
之间的路由
当从 pages/
逐步迁移到 app/
时,Next.js 路由器会自动处理两者之间的硬导航。为了检测从 pages/
到 app/
的转换,有一个客户端路由器过滤器利用概率检查应用路由,偶尔可能会出现误报。默认情况下,这种情况应该非常罕见,因为我们将误报可能性配置为 0.01%。可以通过 next.config.js
中的 experimental.clientRouterFilterAllowedRate
选项自定义此可能性。需要注意的是,降低误报率会增加客户端包中生成的过滤器大小。
或者,如果你希望完全禁用此处理并手动管理 pages/
和 app/
之间的路由,可以在 next.config.js
中将 experimental.clientRouterFilter
设为 false。禁用此功能后,任何与 app 路由重叠的 pages 动态路由默认将无法正确导航。