Next.js 如何通过预提取路由来加快导航速度,以及如何自定义此功能。
在这篇博文中,您将了解 Next.js 中的路由如何运作、如何针对速度进行优化,以及如何自定义路由以最符合您的需求。
<Link> 组件
在 Next.js 中,您无需手动设置路由。Next.js 使用基于文件系统的路由,让您只需在 ./pages/ 目录中创建文件和文件夹:

如需链接到不同的网页,请使用 <Link> 组件,这与使用旧版 <a> 元素的方式类似:
<Link href="/margherita">
<a>Margherita</a>
</Link>
当您使用 <Link> 组件进行导航时,Next.js 会为您做更多事情。通常,当您点击某个链接时,系统会下载相应网页,但 Next.js 会自动预提取呈现该网页所需的 JavaScript。
当您加载包含少量链接的网页时,很可能在您点击某个链接时,该链接后面的组件已经提取完毕。这样可以更快地导航到新页面,从而提高应用响应速度。
在示例应用中,index.js 页面通过 <Link> 链接到 margherita.js:
使用 Chrome 开发者工具验证 margherita.js 是否已预提取:
1. 如需预览网站,请按查看应用。然后按全屏图标 。
- 打开 Chrome 开发者工具。
- 点击网络标签页。
- 选中禁用缓存复选框。
- 重新加载页面。
加载 index.js 时,Network 标签页会显示 margherita.js 也已下载:

自动预取功能的运作方式
Next.js 仅预提取视口中显示的链接,并使用 Intersection Observer API 来检测这些链接。此外,当网络连接速度较慢或用户已开启 Save-Data 时,系统也会停用预提取功能。根据这些检查,Next.js 会动态注入 <link
rel="preload"> 标记,以便下载组件以供后续导航使用。
Next.js 只会提取 JavaScript,而不会执行它。这样,在您访问该链接之前,它不会下载预提取网页可能请求的任何其他内容。
避免不必要的预提取
为避免下载不必要的内容,您可以通过将 <Link> 上 prefetch 属性设置为 false,为很少访问的网页停用预提取:
<Link href="/pineapple-pizza" prefetch={false}>
<a>Pineapple pizza</a>
</Link>
在此第二个示例应用中,index.js 页面具有一个 <Link> 到 pineapple-pizza.js,其中 prefetch 设置为 false:
如需检查网络活动,请按照第一个示例中的步骤操作。当您加载 index.js 时,开发者工具的网络标签页会显示 margherita.js 已下载,但 pineapple-pizza.js 未下载:

使用自定义路由进行预提取
<Link> 组件适用于大多数使用情形,但您也可以构建自己的组件来进行路由。Next.js 通过 next/router 中提供的路由器 API 简化了此流程。如果您想在导航到新路线之前执行某些操作(例如提交表单),可以在自定义路由代码中定义该操作。
如果您使用自定义组件进行路由,也可以向其中添加预提取功能。如需在路由代码中实现预提取,请使用 useRouter 中的 prefetch 方法。
请查看此示例应用中的 components/MyLink.js:
预提取是在 useEffect hook 中完成的。如果 <MyLink> 的 prefetch 属性设置为 true,则在渲染该 <MyLink> 时,系统会预提取 href 属性中指定的路由:
useEffect(() => {
if (prefetch) router.prefetch(href)
});
当您点击链接时,系统会在 handleClick 中完成路由。系统会将一条消息记录到控制台,并且 push 方法会导航到 href 中指定的新路线:
const handleClick = e => {
e.preventDefault();
console.log("Having fun with Next.js.");
router.push(href);
};
在此示例应用中,index.js 页面具有指向 margherita.js 和 pineapple-pizza.js 的 <MyLink>。prefetch 属性在 /margherita 上设置为 true,在 /pineapple-pizza 上设置为 false。
<MyLink href="/margherita" title="Margherita" prefetch={true} />
<MyLink href="/pineapple-pizza" title="Pineapple pizza" prefetch={false} />
加载 index.js 时,“网络”标签页会显示 margherita.js 已下载,而 pineapple-pizza.js 未下载:

当您点击任一链接时,控制台会记录“Having fun with Next.js.”,并导航到新路由:

总结
使用 <Link> 时,Next.js 会自动预提取呈现链接网页所需的 JavaScript,从而加快新网页的导航速度。如果您使用的是自定义路由,则可以使用 Next.js 路由器 API 自行实现预提取。通过为很少访问的网页停用预提取功能,避免不必要地下载内容。