Next.jsのレイアウトパターン

こんにちは。WESEEK の 田村 です。

先日、 Next.js のドキュメントに Layouts のパターンについてのページが追加されました。

https://nextjs.org/docs/basic-features/layouts

Layout コンポーネント

すべてのページに同一のナビゲーションバーやフッターを適用させる場合、下記のように Layout コンポーネントを作成して各ページで再利用できるようにします。

// components/layout.js

import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}

Layout パターン

すべてのページで単一の Layout を適用する

アプリケーション全体で1つの Layout しかない場合は、 Custom App を作成し、 Layout でラップします。
Custom App は、 ./pages/_app.js に下記のように記述してファイルを作成します。
これで、すべてのページの同一の Layout が適用されます。

// pages/_app.js

import Layout from '../components/layout'

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}

Custom App に Layout を記述すると、 Layout コンポーネントはページ遷移をした際に再利用され、 state が保持されます。

ページごとに異なる Layout を適用する

ページごとに異なる Layout を適用させる場合は、各ページコンポーネントに getLayout プロパティを追加します。 getLayout 内には、ページごとの Layout を定義します。

// pages/index.js

import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'

export default function Page() {
  return {
    /** Your content */
  }
}

Page.getLayout = (page) => (
  <Layout>
    <NestedLayout>{page}</NestedLayout>
  </Layout>
)

Custom App には、下記のように記述します。各ページのコンポーネントに getLayout プロパティが定義されている場合はページごとの 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} />)
}

データフェッチ

Layout コンポーネント内では、 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 />
    </>
  )
}

参考にさせていただいたサイト

関連記事

VercelでNext.jsを簡単デプロイ

煩わしい設定は一切なし!Next.jsでCSS を使う方法

CSSをJavaScript に記載する-Next.jsでCSS-in-JS を使う方法