【Next.js和訳】Basic Features/Layouts
この記事について
この記事は、Basic Features/Layoutsの記事を和訳したものです。
記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。
Layouts
React モデルでは、ページを一連のコンポーネントに分解することができます。これらのコンポーネントの多くは、ページ間で再利用されることがよくあります。例えば、すべてのページに同じナビゲーションバーとフッターがあるかもしれません。
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
例
カスタムアプリによる単一の共有レイアウト
アプリケーション全体で 1 つのレイアウトしかない場合は、カスタムアプリを作成して、そのレイアウトでアプリケーションをラップすることができます。<Layout />
コンポーネントはページ変更時に再利用されるため、そのコンポーネントの状態(入力値など)は保持されます。
import Layout from '../components/layout'
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
ページ単位のレイアウト
複数のレイアウトが必要な場合は、ページにgetLayout
というプロパティを追加して、レイアウト用の React コンポーネントを返せるようにします。これにより、ページごとにレイアウトを定義することができます。関数を返しているので、必要に応じて複雑なネストされたレイアウトにすることができます。
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
export default function Page() {
return {
/** コンテンツ */
}
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
export default function MyApp({ Component, pageProps }) {
// ページレベルで定義されたlayoutがある場合はそれを使用する
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
ページ間を移動する際には、シングルページアプリケーション(SPA)の体験のために、ページの state(入力値、スクロール位置など)を保持させます。
このレイアウトパターンでは、ページ遷移の間に React のコンポーネントツリーが維持されるため、state の永続化が可能になります。コンポーネントツリーにより、React はどの要素が変更されたかを理解し、state を保持することができます。
TypeScript について
TypeScript を使用する場合は、まずページ用にgetLayout
関数を含む新しいタイプを作成する必要があります。次に、AppProps
用に新しいタイプを作成し、Component
プロパティをオーバーライドして、先に作成したタイプを使用する必要があります。
import type { ReactElement } from 'react'
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
export default function Page() {
return {
/** コンテンツ */
}
}
Page.getLayout = function getLayout(page: ReactElement) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
type NextPageWithLayout = NextPage & {
getLayout?: (page: ReactElement) => ReactNode
}
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout
}
export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
// ページレベルで定義されたlayoutがある場合はそれを使用する
const getLayout = Component.getLayout ?? ((page) => page)
return getLayout(<Component {...pageProps} />)
}
データのフェッチ
レイアウト内では、useEffect
やSWRなどのライブラリを使って、クライアントサイドでデータを取得することができます。このファイルはPageではないので、現在、getStaticProps
や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 />
</>
)
}
次にすべきことについては、以下のセクションをお勧めします。
Discussion