链接和导航
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
/about
→pages/about.js
/blog/hello-world
→pages/blog/[slug].js
视口中(初始或通过滚动)的任何 <Link />
都将默认预取(包括使用静态生成的页面的相应数据)。服务器渲染路由的相应数据仅在单击 <Link />
时才会被获取。
链接到动态路径
你还可以使用插值来创建路径,这对于动态路由段非常有用。例如,要显示已作为 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 兼容。
或者,使用 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 对象,其中
pathname
是pages
目录中页面的名称。在本例中为/blog/[slug]
。query
是一个包含动态段的对象。在本例中为slug
。
注入路由器
示例
要访问 React 组件中的 router
对象,你可以使用 useRouter
或 withRouter
。
通常,我们建议使用 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,而无需再次运行数据获取方法,包括 getServerSideProps
、getStaticProps
和 getInitialProps
。
你将通过 router
对象(由 useRouter
或 withRouter
添加)接收更新后的 pathname
和 query
,而不会丢失状态。
要启用浅路由,请将 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 })
由于这是一个新页面,即使我们要求执行浅路由,它也会卸载当前页面,加载新页面并等待数据获取。
当浅路由与中间件一起使用时,它不会像以前在没有中间件的情况下那样确保新页面与当前页面匹配。这是因为中间件能够动态重写,并且无法在客户端进行验证,而无需数据获取(浅路由会跳过数据获取),因此浅路由更改必须始终被视为浅路由。
这个有帮助吗?