第4回

コンポーネントとは:UIを部品に分けてHeaderとFooterを作る

Reactのコンポーネント分割を実践。App.tsxに書いたコードをHeader・Footerに切り出す手順と、import/exportの仕組みを解説。

·14分で読める
たける
たける とりあえずApp.tsxにヘッダーもメインも全部書いてみたんですけど、もう100行超えてて……なんか読みにくいです。
りこ
りこ それが分割のタイミング。「スクロールしないと全体が見えない」は分ける合図。

今の状態を確認する

まず、App.tsxに全部書いた状態を作ってみる。

// src/App.tsx(分割前)
function App() {
  return (
    <div>
      {/* ヘッダー */}
      <header>
        <div>
          <span>生成AI時代のReact実践入門</span>
          <nav>
            <a href="/">ホーム</a>
            <a href="/characters">登場人物</a>
          </nav>
        </div>
      </header>

      {/* メイン */}
      <main>
        <h1>Reactを実践的に学ぼう</h1>
        <p>対話形式でReactの基礎から学べるサイトです。</p>
      </main>

      {/* フッター */}
      <footer>
        <p>© 2025 生成AI時代のReact実践入門</p>
      </footer>
    </div>
  )
}

export default App

これが100行、200行と増えていくとどうなるか。どこに何が書いてあるか探すのが大変になる。「ヘッダーのリンクを変えたい」のに、ファイル全体を読まないといけなくなる。

Headerを切り出す

src/components/ フォルダを作り、その中に Header.tsx を作る。

src/
├── components/
│   ├── Header.tsx   ← 新しく作る
│   └── Footer.tsx   ← 新しく作る
├── App.tsx
└── main.tsx
// src/components/Header.tsx
export const Header = () => {
  return (
    <header>
      <div>
        <span>生成AI時代のReact実践入門</span>
        <nav>
          <a href="/">ホーム</a>
          <a href="/characters">登場人物</a>
        </nav>
      </div>
    </header>
  )
}
たける
たける `export const Header` って、`export default` じゃないんですか?
りこ
りこ 2種類ある。`export default` はファイルから1つだけ。`export const` は名前付きエクスポートで、1ファイルに複数書ける。どちらでもいいけど、このプロジェクトは名前付きエクスポートで統一する。

exportとimportの仕組み

コンポーネントを別ファイルに書いたら、使う側で import する必要がある。

// src/App.tsx(分割後)
import { Header } from './components/Header'
import { Footer } from './components/Footer'

function App() {
  return (
    <div>
      <Header />
      <main>
        <h1>Reactを実践的に学ぼう</h1>
        <p>対話形式でReactの基礎から学べるサイトです。</p>
      </main>
      <Footer />
    </div>
  )
}

export default App
たける
たける `'./components/Header'` の `./` って何ですか?
りこ
りこ 「今のファイルからの相対パス」という意味。`App.tsx` から見て、同じ `src/` フォルダの中にある `components/Header` を指している。
たける
たける `.tsx` の拡張子は書かなくていいんですか?
りこ
りこ TypeScript + Viteの組み合わせでは省略できる。書いても動くけど、省略が慣例。

Footerも切り出す

同じ手順で Footer.tsx を作る。

// src/components/Footer.tsx
export const Footer = () => {
  return (
    <footer>
      <p>© 2025 生成AI時代のReact実践入門</p>
    </footer>
  )
}

コンポーネントを分ける基準

たける
たける どのくらいの大きさになったら分ければいいんですか?
りこ
りこ 明確なルールはないけど、目安は3つ。「複数の場所で使う」「ファイルが長くて読みにくい」「役割が明確に分かれている」。今回のHeaderは3つ全部当てはまる。
たける
たける 逆に分けすぎもよくないですか? すごく細かいパーツまで全部ファイルにしてたら、どこに何があるか逆にわからなくなりそう。
りこ
りこ そう。分割はコストでもある。「分けることで読みやすくなるか」を基準にして。最初はざっくりで十分。リファクタリングはいつでもできる。
📁 第4回完了時点のファイル構成・完成コード

フォルダ構成

src/
├── components/
│   ├── Header.tsx   ← 今回追加
│   └── Footer.tsx   ← 今回追加
├── App.tsx          ← Header・Footerをimportするだけに整理
└── main.tsx

Header.tsx

export const Header = () => {
  return (
    <header className="bg-white border-b border-slate-200 sticky top-0 z-10">
      <div className="max-w-5xl mx-auto px-4 sm:px-8 h-14 flex items-center justify-between">
        <span className="font-bold text-slate-900">生成AI時代のReact実践入門</span>
        <nav className="flex items-center gap-6">
          <a href="/" className="text-sm text-slate-600 hover:text-slate-900">ホーム</a>
          <a href="/characters" className="text-sm text-slate-600 hover:text-slate-900">登場人物</a>
        </nav>
      </div>
    </header>
  )
}

Footer.tsx

export const Footer = () => {
  return (
    <footer className="border-t border-slate-200 bg-slate-50 mt-auto">
      <div className="max-w-5xl mx-auto px-4 sm:px-8 py-8 text-center text-sm text-slate-400">
        <p>© 2026 生成AI時代のReact実践入門</p>
      </div>
    </footer>
  )
}

App.tsx

import { Header } from './components/Header'
import { Footer } from './components/Footer'

function App() {
  return (
    <div className="min-h-screen flex flex-col">
      <Header />
      <main className="flex-1">
        {/* 次の回からここにコンテンツを追加していく */}
      </main>
      <Footer />
    </div>
  )
}

export default App

まとめ

  • コンポーネントは関数として定義し、JSXを返す
  • 別ファイルに書いたコンポーネントは export して、使う側で import する
  • 名前付きエクスポートexport const):1ファイルに複数書ける
  • デフォルトエクスポートexport default):1ファイルに1つだけ
  • 分割の目安:「複数の場所で使う」「ファイルが長い」「役割が明確に分かれている」

次の第5回では、JSXの書き方を詳しく見ていく。HTMLとほぼ同じだが、いくつか重要な違いがある。