链接与导航
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`
视口中(最初或通过滚动)的任何 `` 都会默认被预取(包括相应的数据),用于使用静态生成的页面。对于服务器渲染路由,相应的数据
链接到动态路径
你还可以使用插值来创建路径,这对于动态路由段非常有用。例如,要显示一个作为 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 PageURL 将更新为 `/?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 })由于这是一个新页面,它将卸载当前页面,加载新页面,并等待数据获取,即使我们要求进行浅层路由。
当浅层路由与代理一起使用时,它将无法像以前没有代理时那样确保新页面与当前页面匹配。这是因为代理可以动态重写,并且在不进行数据获取(浅层路由跳过了数据获取)的情况下无法在客户端验证,因此浅层路由更改必须始终被视为浅层路由。
这有帮助吗?