注意: 我們在 Next.js 引入了改進佈局的支援。 請閱讀佈局意見徵求來或許更多細節及提供意見回饋。
React 模組允許我們解構一個頁面而生成多個組件。許多組件經常在頁面之間重覆被使用。例如,在每一個頁面,你可能會有相同的導覽列和頁尾。
// components/layout.js import Navbar from './navbar' import Footer from './footer' export default function Layout({ children }) { return ( <> <Navbar /> <main>{children}</main> <Footer /> </> ) }
如果你的應用程式只有一個佈局,你可以建立一個自定義 App然後將你的應用程式包覆在這個佈局中。由於 <Layout />
組件在更換頁面時被重覆使用,其組件狀態將會被保存 (例如:input 值)。
// 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) 使用體驗保有頁面的狀態( input 值,滑動位置等等)。
這種佈局模式,由於 React 組件樹是在頁面之間被維護,這使得狀態可以持續。隨著組件樹,React 可以知道哪一個元素已經更改並保留狀態。
注意: 這種 React 理解哪個元素已經被改變的流程我們稱為協調。
當使用 TypeScript 時,你必須要為你的頁面建立新的 type ,包含一個 getLayout
函式。接著,你必須要為 AppProps
也建立一個新的 type,這個 type 將會覆蓋 Component
屬性進而使用先前建立的 type.
// 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} />) }
在你的佈局中,你可以在客戶端使用 useEffect
或者如 SWR 的函式庫獲取資料。由於這個檔案不是一個頁面,因此目前不能使用 getStaticProps
或 getServerSideProps
。
// 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 /> </> ) }
下一步該做什麼呢?為了學習更多,我們建議你可以跟著以下的部分走: