連結與導航
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 })由於這是一個新頁面,它將解除安裝當前頁面,載入新頁面,並等待資料獲取,即使我們要求進行淺層路由。
當淺層路由與代理一起使用時,它將無法像以前沒有代理時那樣確保新頁面與當前頁面匹配。這是因為代理可以動態重寫,並且在不進行資料獲取(淺層路由跳過了資料獲取)的情況下無法在客戶端驗證,因此淺層路由更改必須始終被視為淺層路由。
這有幫助嗎?