跳到主要内容

链接和导航

在Next.js中,有两种在路由之间导航的方式

  • 使用 <Link> 组件
  • 使用 useRouter Hook

本页面将介绍如何使用 <Link>useRouter(),并深入探讨导航的工作原理。

<Link> 是一个内置组件,它扩展了 HTML 的 <a> 标签, 提供了在路由之间进行预取和客户端导航的功能。 这是在Next.js中导航之间的主要方式。

您可以通过从 next/link 中导入它,并向组件传递一个 href 属性来使用它:

app/page.tsx
import Link from 'next/link'

export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}

还可以向 <Link> 传递其他可选的属性。更多信息请参阅 API 参考。

示例

链接到动态段

在链接到动态段时,您可以使用模板文字和插值来生成链接列表。例如,要生成博客文章列表:

app/blog/PostList.js
import Link from 'next/link'

export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}

检查活动链接

您可以使用 usePathname() 来确定链接是否处于活动状态。 例如,要向活动链接添加类,您可以检查当前pathname是否与链接的 href 匹配:

app/components/links.tsx
'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export function Links() {
const pathname = usePathname()

return (
<nav>
<ul>
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Home
</Link>
</li>
<li>
<Link
className={`link ${pathname === '/about' ? 'active' : ''}`}
href="/about"
>
About
</Link>
</li>
</ul>
</nav>
)
}

滚动到id

Next.js App Router 的默认行为是在导航时滚动到新路由的顶部,或者对于后退和前进导航保持滚动位置。

如果您想要在导航时滚动到特定的标识,可以在URL后附加一个 # 锚链接, 或者只是将一个 # 锚链接传递给 href 属性。这是因为 <Link> 渲染为 <a> 元素,所以是可能的。

<Link href="/dashboard#settings">Settings</Link>

// 输出
<a href="/dashboard#settings">Settings</a>

禁用滚动恢复

Next.js App Router 的默认行为是在导航时滚动到新路由的顶部,或者对于后退和前进导航保持滚动位置。 如果您想要禁用此行为,可以将 scroll={false} 传递给 <Link> 组件, 或者将 scroll: false 传递给 router.push()router.replace()

// next/link
<Link href="/dashboard" scroll={false}>
Dashboard
</Link>

// useRouter
import { useRouter } from 'next/navigation'

const router = useRouter()

router.push('/dashboard', { scroll: false })

useRouter() Hook

useRouter 钩子允许您以编程方式更改路由。

此钩子只能在客户端组件内使用,并且是从 next/navigation 导入的。

app/page.js

'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
const router = useRouter()

return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}

有关 useRouter 方法的完整列表,请参阅 API 参考

备注

除非有使用 useRouter 的特定需求,否则请使用 <Link> 组件在路由之间进行导航。

路由和导航的工作原理

App Router 使用混合方法进行路由和导航。 在服务器上,您的应用程序代码会自动按路由段进行代码拆分。 在客户端上,Next.js 会预取和缓存路由段。 这意味着当用户导航到新路由时,浏览器不会重新加载页面,只有更改的路由段会重新渲染, 从而提高导航体验和性能。

  1. 预取 预取是在用户访问之前在后台预加载路由的一种方式。

在Next.js中,有两种路由的预取方式:

  • <Link> 组件:路由在用户视口中变得可见时会自动进行预取。预取发生在页面首次加载时或通过滚动进入视图时。
  • router.prefetch():可以使用 useRouter 钩子以编程方式进行路由的预取。

对于<Link>的预取行为在

静态和动态路由上是不同的:

  • 静态路由:prefetch 默认为 true。整个路由将被预取和缓存。
  • 动态路由:prefetch 默认为 automatic。 只有共享布局直到第一个 loading.js 文件的路由段被预取和缓存,缓存有效期为30秒。 这降低了获取整个动态路由的成本,并且您可以显示即时的加载状态,以提供更好的视觉反馈。

您可以通过将 prefetch 属性设置为 false 来禁用预取。

有关更多信息,请参阅 <Link> API 参考。

备注

prefetch在开发中未启用,只在生产中启用。

  1. 缓存 Next.js具有一个内存中的客户端端缓存, 称为Router Cache。 当用户在应用程序中导航时, 预取 路由段和访问过的路由的React Server Component Payload都存储在缓存中。

这意味着在导航时,尽可能地重用缓存,而不是向服务器发出新请求, 从而通过减少请求和数据传输的次数来提高性能。

了解有关Router Cache 如何工作以及如何配置它的更多信息。

  1. 部分渲染 部分渲染意味着在客户端上只重新渲染在导航时发生变化的路由段,而保留任何共享段。

例如,在两个兄弟路由之间导航,/dashboard/settings/dashboard/analytics, 将呈现settingsanalytics,并保留共享的仪表板布局。 partial rendering

如果没有部分渲染,每次导航都会导致在服务器上重新渲染整个页面。 只渲染发生变化的段减少了传输的数据量和执行时间,从而提高了性能。

  1. 软导航 默认情况下,浏览器在页面之间执行硬导航。 这意味着浏览器重新加载页面并重置React状态,例如应用程序中的useState钩子和浏览器状态, 例如用户的滚动位置或焦点元素。 然而,在Next.js中,App Router 使用软导航。 这意味着React仅渲染更改的段,同时保留React和浏览器状态,而没有完全重新加载页面。

  2. 后退和前进导航 默认情况下,Next.js会保持后退和前进导航的滚动位置, 并在Router Cache 中重新使用路由段。