レイアウトとページの作成方法

Next.jsではファイルシステムベースのルーティングを使用しており、フォルダとファイルを使ってルートを定義できます。このページでは、レイアウトとページの作成方法、およびそれら間のリンク方法について説明します。

ページの作成

ページとは、特定のルートでレンダリングされるUIです。ページを作成するには、appディレクトリ内にpageファイルを追加し、Reactコンポーネントをデフォルトエクスポートします。例えば、インデックスページ(/)を作成する場合:

page.js特殊ファイル
export default function Page() {
  return <h1>Hello Next.js!</h1>
}

レイアウトの作成

レイアウトとは、複数のページ間で共有されるUIです。ナビゲーション時、レイアウトは状態を保持し、インタラクティブなまま再レンダリングされません。

layoutファイルからReactコンポーネントをデフォルトエクスポートすることでレイアウトを定義できます。このコンポーネントは、ページまたは別のレイアウトとなるchildrenプロップを受け取る必要があります。

例えば、インデックスページを子として受け取るレイアウトを作成するには、appディレクトリ内にlayoutファイルを追加します:

layout.js特殊ファイル
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {/* レイアウトUI */}
        {/* ページまたはネストされたレイアウトをレンダリングしたい場所にchildrenを配置 */}
        <main>{children}</main>
      </body>
    </html>
  )
}

上記のレイアウトはルートレイアウトと呼ばれ、appディレクトリのルートで定義されています。ルートレイアウトは必須で、htmlタグとbodyタグを含める必要があります。

ネストされたルートの作成

ネストされたルートとは、複数のURLセグメントで構成されるルートです。例えば、/blog/[slug]ルートは3つのセグメントで構成されます:

  • /(ルートセグメント)
  • blog(セグメント)
  • [slug](リーフセグメント)

Next.jsでは:

  • フォルダはURLセグメントにマッピングされるルートセグメントを定義するために使用されます
  • ファイルpagelayoutなど)はセグメントに対して表示されるUIを作成するために使用されます

ネストされたルートを作成するには、フォルダを互いに入れ子にします。例えば、/blogのルートを追加するには、appディレクトリ内にblogというフォルダを作成します。そして、/blogを公開可能にするために、page.tsxファイルを追加します:

blogフォルダとpage.jsファイルを示すファイル階層
// ダミーインポート
import { getPosts } from '@/lib/posts'
import { Post } from '@/ui/post'

export default async function Page() {
  const posts = await getPosts()

  return (
    <ul>
      {posts.map((post) => (
        <Post key={post.id} post={post} />
      ))}
    </ul>
  )
}

フォルダをさらにネストすることで、ネストされたルートを作成できます。例えば、特定のブログ投稿のルートを作成するには、blog内に新しい[slug]フォルダを作成し、pageファイルを追加します:

blogフォルダ内にネストされたslugフォルダとpage.jsファイルを示すファイル階層
function generateStaticParams() {}

export default function Page() {
  return <h1>Hello, Blog Post Page!</h1>
}

フォルダ名を角括弧で囲む(例:[slug])ことで、動的ルートセグメントを作成し、データから複数のページを生成できます。例:ブログ投稿、商品ページなど。

レイアウトのネスト

デフォルトでは、フォルダ階層内のレイアウトもネストされており、childrenプロップを介して子レイアウトをラップします。特定のルートセグメント(フォルダ)内にlayoutを追加することでレイアウトをネストできます。

例えば、/blogルートのレイアウトを作成するには、blogフォルダ内に新しいlayoutファイルを追加します。

ルートレイアウトがblogレイアウトをラップしているファイル階層
export default function BlogLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <section>{children}</section>
}

上記の2つのレイアウトを組み合わせると、ルートレイアウト(app/layout.js)がブログレイアウト(app/blog/layout.js)をラップし、それがブログ(app/blog/page.js)とブログ投稿ページ(app/blog/[slug]/page.js)をラップします。

動的セグメントの作成

動的セグメントを使用すると、データから生成されるルートを作成できます。例えば、個々のブログ投稿ごとに手動でルートを作成する代わりに、ブログ投稿データに基づいてルートを生成する動的セグメントを作成できます。

動的セグメントを作成するには、セグメント(フォルダ)名を角括弧で囲みます:[segmentName]。例えば、app/blog/[slug]/page.tsxルートでは、[slug]が動的セグメントです。

export default async function BlogPostPage({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  const post = await getPost(slug)

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  )
}

動的セグメントについてさらに学びましょう。

ページ間のリンク

<Link>コンポーネントを使用してルート間をナビゲートできます。<Link>はNext.jsに組み込まれたコンポーネントで、HTMLの<a>タグを拡張し、プリフェッチクライアントサイドナビゲーションを提供します。

例えば、ブログ投稿のリストを生成するには、next/linkから<Link>をインポートし、hrefプロップをコンポーネントに渡します:

import Link from 'next/link'

export default async function Post({ post }) {
  const posts = await getPosts()

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

<Link>はNext.jsアプリケーションでルート間をナビゲートする主要かつ推奨される方法です。ただし、より高度なナビゲーションにはuseRouterフックも使用できます。

On this page