跳到主要內容
建置您的應用程式路由頁面和版面配置

頁面和版面配置

Pages Router 具有基於檔案系統的路由器,建立在頁面的概念之上。

當檔案新增至 pages 目錄時,它會自動作為路由提供。

在 Next.js 中,頁面是從 pages 目錄中的 .js.jsx.ts.tsx 檔案匯出的 React 元件。每個頁面都根據其檔案名稱與路由相關聯。

範例:如果您建立 pages/about.js,其中匯出如下所示的 React 元件,則可以透過 /about 存取它。

export default function About() {
  return <div>About</div>
}

索引路由

路由器會自動將名為 index 的檔案路由到目錄的根目錄。

  • pages/index.js/
  • pages/blog/index.js/blog

巢狀路由

路由器支援巢狀檔案。如果您建立巢狀資料夾結構,檔案仍會以相同方式自動路由。

  • pages/blog/first-post.js/blog/first-post
  • pages/dashboard/settings/username.js/dashboard/settings/username

具有動態路由的頁面

Next.js 支援具有動態路由的頁面。例如,如果您建立一個名為 pages/posts/[id].js 的檔案,則可以透過 posts/1posts/2 等存取它。

若要深入瞭解動態路由,請查看動態路由文件

版面配置模式

React 模型允許我們將頁面解構為一系列元件。許多這些元件通常在頁面之間重複使用。例如,您可能在每個頁面上都有相同的導覽列和頁尾。

components/layout.js
import Navbar from './navbar'
import Footer from './footer'
 
export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}

範例

使用自訂 App 的單一共享版面配置

如果您的整個應用程式只有一個版面配置,您可以建立自訂 App,並使用該版面配置包裝您的應用程式。由於 <Layout /> 元件在變更頁面時會重複使用,因此其元件狀態將會保留 (例如輸入值)。

pages/_app.js
import Layout from '../components/layout'
 
export default function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}

單頁版面配置

如果您需要多個版面配置,您可以將屬性 getLayout 新增至您的頁面,讓您可以傳回版面配置的 React 元件。這可讓您在單頁的基礎上定義版面配置。由於我們傳回的是函式,因此如果需要,我們可以擁有複雜的巢狀版面配置。

pages/index.js
 
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
 
export default function Page() {
  return (
    /** Your content */
  )
}
 
Page.getLayout = function getLayout(page) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}
pages/_app.js
export default function MyApp({ Component, pageProps }) {
  // Use the layout defined at the page level, if available
  const getLayout = Component.getLayout ?? ((page) => page)
 
  return getLayout(<Component {...pageProps} />)
}

在頁面之間導航時,我們希望保留頁面狀態 (輸入值、捲動位置等),以獲得單頁應用程式 (SPA) 體驗。

此版面配置模式可實現狀態持久性,因為 React 元件樹在頁面轉換之間保持不變。透過元件樹,React 可以瞭解哪些元素已變更以保留狀態。

小知識:此過程稱為協調,這是 React 瞭解哪些元素已變更的方式。

使用 TypeScript

使用 TypeScript 時,您必須先為您的頁面建立一個新的類型,其中包含 getLayout 函式。然後,您必須為您的 AppProps 建立一個新的類型,覆寫 Component 屬性以使用先前建立的類型。

pages/index.tsx
import type { ReactElement } from 'react'
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
import type { NextPageWithLayout } from './_app'
 
const Page: NextPageWithLayout = () => {
  return <p>hello world</p>
}
 
Page.getLayout = function getLayout(page: ReactElement) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}
 
export default Page
pages/_app.tsx
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
 
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode
}
 
type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout
}
 
export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  // Use the layout defined at the page level, if available
  const getLayout = Component.getLayout ?? ((page) => page)
 
  return getLayout(<Component {...pageProps} />)
}

資料抓取

在您的版面配置中,您可以使用 useEffectSWR 等函式庫在客戶端抓取資料。由於此檔案不是頁面,因此您目前無法使用 getStaticPropsgetServerSideProps

components/layout.js
import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'
 
export default function Layout({ children }) {
  const { data, error } = useSWR('/api/navigation', fetcher)
 
  if (error) return <div>Failed to load</div>
  if (!data) return <div>Loading...</div>
 
  return (
    <>
      <Navbar links={data.links} />
      <main>{children}</main>
      <Footer />
    </>
  )
}