こんにちは。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 />
</>
)
}