链接和导航
Next.js 路由允许你在页面之间进行客户端路由转换,类似于单页面应用。
¥The Next.js router allows you to do client-side route transitions between pages, similar to a single-page application.
提供了一个名为 Link
的 React 组件来执行此客户端路由转换。
¥A React component called Link
is provided to do this client-side route transition.
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
) 映射到已知页面:
¥The example above uses multiple links. Each one maps a path (href
) to a known page:
-
/
→pages/index.js
-
/about
→pages/about.js
-
/blog/hello-world
→pages/blog/[slug].js
对于使用 静态生成 的页面,默认情况下将预取视口中的任何 <Link />
(初始或通过滚动)(包括相应的数据)。仅当点击 <Link />
时才会获取 server-rendered 路由的相应数据。
¥Any <Link />
in the viewport (initially or through scroll) will be prefetched by default (including the corresponding data) for pages using Static Generation. The corresponding data for server-rendered routes is fetched only when the <Link />
is clicked.
链接到动态路径
¥Linking to dynamic paths
你还可以使用插值来创建路径,这对于 动态路由段 很方便。例如,要显示已作为 prop 传递给组件的帖子列表:
¥You can also use interpolation to create the path, which comes in handy for dynamic route segments. For example, to show a list of posts which have been passed to the component as a prop:
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 兼容。¥
encodeURIComponent
is used in the example to keep the path utf-8 compatible.
或者,使用 URL 对象:
¥Alternatively, using a URL Object:
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 对象,其中:
¥Now, instead of using interpolation to create the path, we use a URL object in href
where:
-
pathname
是pages
目录中页面的名称。在本例中为/blog/[slug]
。¥
pathname
is the name of the page in thepages
directory./blog/[slug]
in this case. -
query
是具有动态段的对象。在本例中为slug
。¥
query
is an object with the dynamic segment.slug
in this case.
注入路由
¥Injecting the router
Examples
要访问 React 组件中的 router
对象,你可以使用 useRouter
或 withRouter
。
¥To access the router
object in a React component you can use useRouter
or withRouter
.
一般来说我们建议使用 useRouter
。
¥In general we recommend using useRouter
.
命令式路由
¥Imperative Routing
next/link
应该能够满足你的大部分路由需求,但你也可以在没有它的情况下进行客户端导航,看看 next/router
的文档。
¥next/link
should be able to cover most of your routing needs, but you can also do client-side navigations without it, take a look at the documentation for next/router
.
以下示例展示了如何使用 useRouter
进行基本页面导航:
¥The following example shows how to do basic page navigations with 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>
)
}
浅层路由
¥Shallow Routing
Examples
浅层路由允许你更改 URL,而无需再次运行数据获取方法,包括 getServerSideProps
、getStaticProps
和 getInitialProps
。
¥Shallow routing allows you to change the URL without running data fetching methods again, that includes getServerSideProps
, getStaticProps
, and getInitialProps
.
你将通过 router
对象(由 useRouter
或 withRouter
添加)收到更新的 pathname
和 query
,而不会丢失状态。
¥You'll receive the updated pathname
and the query
via the router
object (added by useRouter
or withRouter
), without losing state.
要启用浅层路由,请将 shallow
选项设置为 true
。考虑以下示例:
¥To enable shallow routing, set the shallow
option to true
. Consider the following example:
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
,并且页面不会被替换,仅更改路由的状态。
¥The URL will get updated to /?counter=10
and the page won't get replaced, only the state of the route is changed.
你还可以通过 componentDidUpdate
观察 URL 变化,如下所示:
¥You can also watch for URL changes via componentDidUpdate
as shown below:
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
}
}
注意事项
¥Caveats
浅层路由仅适用于当前页面的 URL 变化。例如,假设我们有另一个名为 pages/about.js
的页面,并且你运行以下命令:
¥Shallow routing only works for URL changes in the current page. For example, let's assume we have another page called pages/about.js
, and you run this:
router.push('/?counter=10', '/about?counter=10', { shallow: true })
由于这是一个新页面,因此即使我们要求进行浅层路由,它也会卸载当前页面,加载新页面并等待数据获取。
¥Since that's a new page, it'll unload the current page, load the new one and wait for data fetching even though we asked to do shallow routing.
当浅层路由与中间件一起使用时,它不会像以前没有中间件那样确保新页面与当前页面匹配。这是因为中间件能够动态重写,并且如果没有浅层跳过的数据获取就无法在客户端进行验证,因此浅层路由更改必须始终被视为浅层。
¥When shallow routing is used with middleware it will not ensure the new page matches the current page like previously done without middleware. This is due to middleware being able to rewrite dynamically and can't be verified client-side without a data fetch which is skipped with shallow, so a shallow route change must always be treated as shallow.