頁面和佈局
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
巢狀路由
Next.js 支援具有動態路由的頁面。例如,如果您建立名為 pages/posts/[id].js
的檔案,則它將可在 posts/1
、posts/2
等網址存取。
要深入了解動態路由,請查閱動態路由文件。
佈局模式
React 模型允許我們將頁面解構為一系列元件。許多這些元件經常在不同頁面之間重複使用。例如,您可能希望每個頁面都有相同的導覽列和頁尾。
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
範例
使用自訂 App 的單一共享佈局
如果您的整個應用程式只有一個佈局,您可以建立一個自訂 App並用該佈局包覆您的應用程式。由於在切換頁面時會重複使用 <Layout />
元件,因此其元件狀態將會被保留(例如輸入值)。
import Layout from '../components/layout'
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
每頁佈局 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>
)
}
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>
)
}
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
屬性以使用先前建立的類型。
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
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} />)
}
資料擷取
在您的佈局內,您可以使用 useEffect
或像是 SWRgetStaticProps
或 getServerSideProps
。
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 />
</>
)
}