跳至内容

链接和导航

Next.js 路由器允许你在页面之间执行客户端路由转换,类似于单页应用程序。

提供了一个名为 Link 的 React 组件来执行此客户端路由转换。

import Link from 'next/link'
 
function Home() {
  return (
    <ul>
      <li>
        <Link href="/">Home</Link>
      </li>
      <li>
        <Link href="/about">About Us</Link>
      </li>
      <li>
        <Link href="/blog/hello-world">Blog Post</Link>
      </li>
    </ul>
  )
}
 
export default Home

上面的示例使用了多个链接。每个链接都将路径 (href) 映射到已知的页面

  • /pages/index.js
  • /aboutpages/about.js
  • /blog/hello-worldpages/blog/[slug].js

视口中的任何 <Link />(最初或通过滚动)都将默认预取(包括相应的数据),适用于使用 静态生成 的页面。对于 服务器渲染 路由,只有在点击 <Link /> 时才会获取相应的数据。

链接到动态路径

你还可以使用插值来创建路径,这对于 动态路由段 非常有用。例如,要显示已作为道具传递给组件的帖子列表

import Link from 'next/link'
 
function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${encodeURIComponent(post.slug)}`}>
            {post.title}
          </Link>
        </li>
      ))}
    </ul>
  )
}
 
export default Posts

encodeURIComponent 用于确保路径与 utf-8 兼容。

或者,使用 URL 对象

import Link from 'next/link'
 
function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link
            href={{
              pathname: '/blog/[slug]',
              query: { slug: post.slug },
            }}
          >
            {post.title}
          </Link>
        </li>
      ))}
    </ul>
  )
}
 
export default Posts

现在,我们不再使用插值来创建路径,而是在 href 中使用 URL 对象,其中

  • pathnamepages 目录中页面的名称。在本例中为 /blog/[slug]
  • query 是一个包含动态段的对象。在本例中为 slug

注入路由器

示例

要访问 React 组件中的 router 对象,可以使用 useRouterwithRouter

一般建议使用 useRouter

命令式路由

next/link 应该能够满足你大多数路由需求,但你也可以在没有它的情况下执行客户端导航,请查看 next/router 的文档

以下示例演示了如何使用 useRouter 执行基本的页面导航

import { useRouter } from 'next/router'
 
export default function ReadMore() {
  const router = useRouter()
 
  return (
    <button onClick={() => router.push('/about')}>
      Click here to read more
    </button>
  )
}

浅路由

示例

浅路由允许您更改 URL 而不再次运行数据获取方法,包括 getServerSidePropsgetStaticPropsgetInitialProps

您将通过 router 对象(由 useRouterwithRouter 添加)接收更新后的 pathnamequery,而不会丢失状态。

要启用浅路由,请将 shallow 选项设置为 true。请考虑以下示例

import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
// Current URL is '/'
function Page() {
  const router = useRouter()
 
  useEffect(() => {
    // Always do navigations after the first render
    router.push('/?counter=10', undefined, { shallow: true })
  }, [])
 
  useEffect(() => {
    // The counter changed!
  }, [router.query.counter])
}
 
export default Page

URL 将更新为 /?counter=10,并且页面不会被替换,只会更改路由的状态。

您还可以通过 componentDidUpdate 监视 URL 更改,如下所示

componentDidUpdate(prevProps) {
  const { pathname, query } = this.props.router
  // verify props have changed to avoid an infinite loop
  if (query.counter !== prevProps.router.query.counter) {
    // fetch data based on the new query
  }
}

注意事项

浅路由**仅**适用于当前页面中的 URL 更改。例如,假设我们有另一个名为 pages/about.js 的页面,并且您运行以下代码

router.push('/?counter=10', '/about?counter=10', { shallow: true })

由于这是一个新页面,它将卸载当前页面,加载新页面并等待数据获取,即使我们要求进行浅路由。

当浅路由与中间件一起使用时,它不会像以前在没有中间件的情况下那样确保新页面与当前页面匹配。这是因为中间件能够动态地重写,并且在没有数据获取的情况下无法在客户端进行验证,而浅路由会跳过数据获取,因此浅路由更改必须始终被视为浅路由。