Lang x Lang

Pages and Layouts

Pages Router は、ページの概念に基づいて構築されたファイルシステムベースの router を持っています。

ファイルが pages ディレクトリに追加されると、それは自動的に route として利用できます。

Next.js では、ページは、pages ディレクトリの .js.jsx.ts、または .tsx ファイルからエクスポートされるReact Component です。各ページは、そのファイル名に基づいた route に関連付けられています。

: 下記のような React component をエクスポートする pages/about.js を作成すると、/about でアクセス可能になります。

export default function About() {
  return <div>About</div>;
}

Index routes

router は、indexと名付けられたファイルをディレクトリの root に自動的に route します。

  • pages/index.js/
  • pages/blog/index.js/blog

Nested routes

この router はネストされたファイルをサポートしています。ネストされたフォルダ構造を作成すると、ファイルは自動的に同じようにルーティングされます。

  • pages/blog/first-post.js/blog/first-post
  • pages/dashboard/settings/username.js/dashboard/settings/username

Pages with Dynamic Routes

Next.js は、dynamic routes を含むページをサポートします。たとえば、pages/posts/[id].jsというファイルを作成すると、posts/1posts/2などでアクセスできます。

詳しくは Dynamic ルーティングについては、dynamic Routing documentationをご覧ください。

Layout Pattern

React モデルでは、pageを一連の Component に分解することが可能です。これらの Component の多くは、ページ間で頻繁に再利用されます。例えば、すべてのページで同じナビゲーションバーとフッターを使用する可能性があります。

components/layout.js
import Navbar from './navbar'
import Footer from './footer'

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

Examples

シングル共有の Layout とカスタムの App

あなたがアプリケーション全体で 1 つだけの layout を持っている場合、Custom Appを作成し、そのアプリケーションを layout で包むことができます。 <Layout /> component はページを変更するときに再利用されるため、その component の状態は保持されます(例:入力値)。

pages/_app.js
import Layout from '../components/layout'

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

ページごとの Layout

複数のレイアウトが必要な場合は、getLayoutプロパティをページに追加して、 React component を layout として返すことができます。これにより、ページごとの基準 で 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>
  )
}
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)の経験のために、ページの状態(入力値、scroll の位置、など)を persist したいと考えています。

この layout パターンは、ページの遷移間で React component ツリーが維持されるため、状態の持続性を可能にします。 component ツリーにより、React はどの要素が変更されたかを理解し、状態を保持することができます。

Good to know: このプロセスは調整 と呼ばれ、これが React がどの要素が変更されたかを理解する方法です。

TypeScript と一緒に

TypeScript を使用するとき、まずgetLayout関数を含むあなたのページの新しい type を作成する必要があります。次に、先ず作成した type を使用するために、あなたの AppPropsの新しい type を作成して Componentプロパティをオーバーライドする必要があります。

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/index.js
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'

const Page = () => {
  return <p>hello world</p>
}

Page.getLayout = function getLayout(page) {
  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} />)
}
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 のような library を使ってクライアントサイドでデータを fetch することができます。このファイルはPageではないため、現在getStaticPropsgetServerSidePropsは使うことができません。

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 />
    </>
  )
}

当社サイトでは、Cookie を使用しています。各規約をご確認の上ご利用ください:
Cookie Policy, Privacy Policy および Terms of Use