链接和导航
Next.js 路由器允许你在页面之间进行客户端路由转换,类似于单页面应用。
提供了一个名为 Link 的 React 组件来实现这种客户端路由转换。
import Link from 'next/link'
function Home() {
return (
<ul>
<li>
<Link href="/">首页</Link>
</li>
<li>
<Link href="/about">关于我们</Link>
</li>
<li>
<Link href="/blog/hello-world">博客文章</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')}>
点击此处阅读更多
</button>
)
}浅层路由
示例
浅层路由允许你更改 URL 而不再次运行数据获取方法,包括 getServerSideProps、getStaticProps 和 getInitialProps。
你将通过 router 对象(由 useRouter 或 withRouter 添加)接收更新的 pathname 和 query,而不会丢失状态。
要启用浅层路由,将 shallow 选项设置为 true。考虑以下示例:
import { useEffect } from 'react'
import { useRouter } from 'next/router'
// 当前 URL 是 '/'
function Page() {
const router = useRouter()
useEffect(() => {
// 总是在第一次渲染后进行导航
router.push('/?counter=10', undefined, { shallow: true })
}, [])
useEffect(() => {
// 计数器已更改!
}, [router.query.counter])
}
export default PageURL 将更新为 /?counter=10,并且页面不会被替换,只有路由的状态发生变化。
你还可以通过 componentDidUpdate 监听 URL 变化,如下所示:
componentDidUpdate(prevProps) {
const { pathname, query } = this.props.router
// 验证 props 是否已更改以避免无限循环
if (query.counter !== prevProps.router.query.counter) {
// 根据新的查询获取数据
}
}注意事项
浅层路由仅适用于当前页面的 URL 更改。例如,假设我们有另一个名为 pages/about.js 的页面,并且你运行:
router.push('/?counter=10', '/about?counter=10', { shallow: true })由于这是一个新页面,它将卸载当前页面,加载新页面,并等待数据获取,即使我们要求进行浅层路由。
当浅层路由与 proxy 一起使用时,它不会像之前在没有 proxy 的情况下那样确保新页面匹配当前页面。这是因为 proxy 可以动态重写,并且无法在客户端进行验证,而不进行数据获取,而浅层路由会跳过这一步,因此浅层路由更改必须始终被视为浅层。