第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.tsxHeader.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とほぼ同じだが、いくつか重要な違いがある。