Next.js 客户端导航与预取
Next.js App Router 用 Link、客户端 Router、按路由代码分割与预取实现 SPA-like navigation,同时继续加载服务端组件结果而不是每次整页刷新。
[!info] related notes
- 所属 MOC:
- 相关概念: react-server-components、resource-hints
- 易混淆概念:
- 相关资源:
Next.js 客户端导航与预取
范围
这篇笔记解释 Next.js App Router 为什么同时具有:
Server-driven rendering
+
SPA-like navigation
也就是:页面可以大量依赖 Server Components,但用户在站内点击链接时仍不必每次都完整刷新整个文档。
<Link> 不只是 <a> 的语法糖
普通:
<a href="/dashboard">Dashboard</a>
会遵循浏览器原生导航语义。
Next.js 通常使用:
import Link from "next/link"
<Link href="/dashboard">Dashboard</Link>
它保留链接语义,同时允许 Next.js Router 接管站内导航并复用当前应用壳。
SPA-like Navigation
初次访问时可以由服务器生成页面;后续站内导航则由客户端 Router 协调:
首次访问
Browser
↓
Server render / RSC
↓
HTML + RSC data + client JS
后续点击 <Link>
↓
Client Router
↓
请求目标 Route 所需结果
↓
局部更新 React tree
因此:
Server Components
≠
每次导航都必须 full page reload
Route-level Code Splitting
Next.js 可以按路由边界拆分需要的代码,让访问 /goals 时不必先下载 /settings、/admin 等页面全部客户端代码。
核心目标:
当前 route 需要什么
↓
只加载相关代码/数据
这降低初始客户端负担。
Prefetch
<Link> 的一个重要能力是:在合适条件下,目标 route 还没真正点击之前就可以提前准备部分资源或路由数据。
可以把它理解为:
用户可能即将访问 /goals/123
↓
prefetch
↓
提前准备 route 需要的资源
↓
真正点击时减少等待
Prefetch 的价值是优化感知导航延迟,而不是改变业务数据的一致性规则。
Prefetch 不等于普通 HTTP Resource Hint
浏览器有通用 prefetch / preload 等 Resource Hints;Next.js route prefetch 则是框架级路由机制,知道目标 route、RSC 数据与应用路由树。
因此不要简单理解为:
Next.js prefetch = 随便提前下载一个 JS 文件
它服务的是应用导航。
Server-driven + Client navigation 为什么不矛盾
假设:
/goals/123
目标页面主要是 Server Component,需要服务端查询 Goal。
用户从 /goals 点击进去时,可以发生:
Client Router 捕获导航
↓
向 Next.js Server 请求新 route 的服务端结果
↓
返回 RSC / route data
↓
React 合并新的 Server Component tree
↓
保留能复用的 layout/client state
因此“路由在客户端切换”和“页面组件在服务端执行”是可以同时成立的。
不要把客户端导航等同于 CSR
客户端 Router 参与导航,只说明:
浏览器没有做一次传统的完整文档刷新。
它并不说明:
页面内容必须完全由浏览器 React 从零生成。
所以:
Client-side navigation ≠ Client-side rendering
这和前面学到的:
Client Component ≠ CSR
属于同一种“不要把不同维度混起来”的思维。
何时仍会发生完整导航
并不是任何情况都必须由 Next.js Router 接管。例如:
- 跳转外站
- 显式使用浏览器级导航
- 某些跨根布局边界的场景
- 用户刷新页面
这时会重新发生完整文档请求。
最短记忆方式
<Link>
↓
client router
↓
prefetch + code splitting
↓
请求新 route 所需结果
↓
局部更新 React tree
所以 Next.js 可以同时做到:服务端组织页面 + 类 SPA 的快速站内导航。