Next.jsによるWebアプリケーション開発概論

UI部品を分割して組み立てる【演習】

9Next.js基礎:ReactコンポーネントとJSX・Propsの基本
Next.jsTailwind CSSアプリ開発開発Web開発

この節で学ぶこと

この節では、UIを小さな部品に分けて、最後に組み立てる 練習をします。

React 公式では、UI はコンポーネントのツリーとして考えると理解しやすく、まず UI をコンポーネント階層に分解することが出発点だと説明しています。

Next.js では、app 配下にページを置き、再利用部品を別ファイルへ切り出して使う構成が自然です。

今回のゴールは、最後に 「見出し・説明文・ボタン」を持つ小さな UI カード を、自分で分割して組み立てることです。

途中はかなりシンプルに進めます。最初は「表示だけ」の部品、次に props を受け取る部品、最後に複数部品を組み合わせた小さな UI に進みます。

React ではコンポーネントは JavaScript の関数として定義し、props で中身を変え、必要ならイベントハンドラも props として渡せます。

最初に持っておきたい見方

UI は部品の集合

たとえば、次のような画面を考えます。

  • ページタイトル
  • お知らせカード
  • カードの見出し
  • カードの本文
  • ボタン

これを 1 ファイルへ全部書くこともできます。

でも、React の考え方では、意味のあるまとまりごとに部品へ分ける 方が読みやすく、直しやすく、再利用しやすくなります。

React 公式でも、コンポーネントは小さなボタンにも大きなページにもなり得ると説明されています。

Next.js ではページと部品を分けて考える

Next.js の App Router では、page.tsx が route-unique UI を返すページの入口です。

そこから、必要に応じて別ファイルのコンポーネントを import して組み立てます。

プロジェクト構造の公式説明でも、app がルーティング中心で、その他の部品や補助コードは別ディレクトリに整理できると案内されています。

今回は、次のような構成で進めます。

src/
  app/
    page.tsx
  components/
    SectionTitle.tsx
    InfoCard.tsx
    PrimaryButton.tsx

練習1 最小の表示部品を作る

問題

SectionTitle というコンポーネントを作ってください。条件は次のとおりです。

  • ファイル名は src/components/SectionTitle.tsx
  • <h2> を返す
  • 表示文字は「お知らせ」
  • export default function SectionTitle() の形で書く

答え

export default function SectionTitle() {
  return <h2>お知らせ</h2>
}

解説

React 公式では、コンポーネントは マークアップを返す JavaScript 関数 です。まずは props なしで固定表示の部品を作るのが最初の練習として分かりやすいです。大文字始まりの名前にするのも React の基本ルールです。

page.tsx で使ってみる

次に src/app/page.tsx で使います。

import SectionTitle from '@/components/SectionTitle'

export default function Page() {
  return (
    <main>
      <SectionTitle />
    </main>
  )
}

これで、「部品を作る → export する → import して使う」という流れが 1 回つながります。React 公式の “Your First Component” でも、この流れが基礎として扱われています。

練習2 Props で中身を変える

問題

SectionTitle を、外から文字を受け取れるように変更してください。条件は次のとおりです。

  • text という props を受け取る
  • 型は string
  • <h2> の中に text を表示する

答え

type SectionTitleProps = {
  text: string
}

export default function SectionTitle({
  text,
}: SectionTitleProps) {
  return <h2>{text}</h2>
}

解説

React 公式では、props は親コンポーネントから子コンポーネントへ情報を渡す仕組みです。TypeScript で型を付けると、何を受け取る部品なのかがはっきりします。分割代入で受け取る書き方も、React では一般的です。

page.tsx 側の使い方

import SectionTitle from '@/components/SectionTitle'

export default function Page() {
  return (
    <main>
      <SectionTitle text="お知らせ" />
      <SectionTitle text="新着情報" />
    </main>
  )
}

ここで大事なのは、同じ部品を中身だけ変えて再利用できる ことです。props の価値はここにあります。

練習3 本文付きカードを作る

問題

InfoCard というコンポーネントを作ってください。条件は次のとおりです。

  • ファイル名は src/components/InfoCard.tsx
  • titlemessage を props で受け取る
  • title<h3>
  • message<p>
  • 全体を <section> で包む

答え

type InfoCardProps = {
  title: string
  message: string
}

export default function InfoCard({
  title,
  message,
}: InfoCardProps) {
  return (
    <section>
      <h3>{title}</h3>
      <p>{message}</p>
    </section>
  )
}

解説

これは、ただの文章表示を 1 つの意味ある部品にした例です。React 公式の考え方では、UI は意味のあるまとまりへ分けるのが基本です。タイトルと本文が常にセットで現れるなら、1 コンポーネントとしてまとめる価値があります。

page.tsx で使う

import SectionTitle from '@/components/SectionTitle'
import InfoCard from '@/components/InfoCard'

export default function Page() {
  return (
    <main>
      <SectionTitle text="お知らせ" />

      <InfoCard
        title="営業時間の変更"
        message="来週から営業時間が変更になります。"
      />

      <InfoCard
        title="新商品の入荷"
        message="本革バッグの新色が入荷しました。"
      />
    </main>
  )
}

ここまで来ると、「ページ」と「部品」の役割がかなり見えてきます。

page.tsx は全体の組み立て担当、InfoCard は 1 件表示担当です。

練習4 ボタン部品を作る

問題

PrimaryButton というコンポーネントを作ってください。条件は次のとおりです。

  • ファイル名は src/components/PrimaryButton.tsx
  • label を props で受け取る
  • onAction を props で受け取る
  • onAction の型は () => void
  • <button>onClickonAction を渡す

答え

'use client'

type PrimaryButtonProps = {
  label: string
  onAction: () => void
}

export default function PrimaryButton({
  label,
  onAction,
}: PrimaryButtonProps) {
  return <button onClick={onAction}>{label}</button>
}

解説

React 公式では、イベントハンドラは JSX に 関数として渡す のが基本です。onClick={onAction} は正しく、onClick={onAction()} は誤りです。

また、Next.js の App Router では、イベントハンドラを使うコンポーネントは基本的に Client Component 側に置くため、'use client' が必要です。

page.tsx で使う

import SectionTitle from '@/components/SectionTitle'
import InfoCard from '@/components/InfoCard'
import PrimaryButton from '@/components/PrimaryButton'

export default function Page() {
  function handleClick() {
    alert('確認しました')
  }

  return (
    <main>
      <SectionTitle text="お知らせ" />

      <InfoCard
        title="営業時間の変更"
        message="来週から営業時間が変更になります。"
      />

      <PrimaryButton
        label="確認する"
        onAction={handleClick}
      />
    </main>
  )
}

ここで、部品に「表示」だけでなく「振る舞い」も持たせられるようになります。

UI が少し生きてきます。

練習5 最後の組み立て

問題

ここまで作った SectionTitleInfoCardPrimaryButton を使って、次のようなシンプル UI を作ってください。

  • ページタイトルは「ダッシュボード」
  • セクション見出しは「今日のお知らせ」
  • カードを 2 件表示する
  • 一番下に「詳細を見る」ボタンを置く
  • ボタンを押すと alert('詳細ページへ') を出す

答え

import SectionTitle from '@/components/SectionTitle'
import InfoCard from '@/components/InfoCard'
import PrimaryButton from '@/components/PrimaryButton'

export default function Page() {
  function handleDetailClick() {
    alert('詳細ページへ')
  }

  return (
    <main>
      <h1>ダッシュボード</h1>

      <SectionTitle text="今日のお知らせ" />

      <InfoCard
        title="サーバーメンテナンス"
        message="本日 22:00 から短時間のメンテナンスを行います。"
      />

      <InfoCard
        title="新機能の追加"
        message="通知設定のカスタマイズ機能が利用できるようになりました。"
      />

      <PrimaryButton
        label="詳細を見る"
        onAction={handleDetailClick}
      />
    </main>
  )
}

解説

これで、1つのページを 複数の小さな部品 から組み立てる体験ができました。

React 公式の “Thinking in React” の考え方に沿えば、これは UI を小さなまとまりへ分け、親コンポーネントで組み立てた形です。

また、Next.js では page.tsx が route-unique UI を返すページの入口なので、このように部品を import して構成するのが自然です。

参考になる外部ページ

Next.js の公式コンポーネント一覧

Next.js の公式で「どんなコンポーネント API があるか」をまとめて見たいなら、API Reference の Components 一覧 が最も見やすいです。ここには FontForm ComponentImage ComponentLink ComponentScript Component がまとまっています。Next.js の現行ドキュメント上でも、この一覧が公式の入口になっています。

特に最初に見やすいのは次のページです。

  • Components - API Reference

Next.js のコンポーネント一覧を見る入口。

  • Project Structure

どこへ部品を置くと整理しやすいかを確認するページ。

  • Layouts and Pagespage.tsxlayout.tsx の役割を確認するページ。

まとめ

今回の演習で大切だったのは、難しい UI を作ることではなく、小さな部品を作って、それを最後に組み立てる感覚 をつかむことです。

SectionTitleInfoCardPrimaryButton の3つはどれも単純ですが、組み合わせると 1 つのページらしく見えます。React 公式の考え方でも、UI はコンポーネントのツリーとして組み立てるものです。

この節で理解してほしいのは次の4点です。

  • コンポーネントは小さく始めてよい。
  • props を使うと同じ部品を使い回せる。
  • イベント処理を付ける部品は Next.js では Client Component 側で考える。
  • page.tsx は部品を組み立てる場所として考えると分かりやすい。

参考文献

  • React Docs, Your First Component.
  • React Docs, Passing Props to a Component.
  • React Docs, Responding to Events.
  • Next.js Docs, API Reference: Components.
  • Next.js Docs, Getting Started: Project Structure.
  • Next.js Docs, Getting Started: Layouts and Pages.
教材トップへ戻る