コンポーネント分割とは
コンポーネント分割は、ざっくり言うと「画面を小さな部品に分解して、意味のある単位ごとに整理すること」です。
ひとつのコンポーネントの中に、ヘッダーも、メインも、フッターも、ボタンも、フォームも、全部書き込んでしまうと、すぐに 100 行・200 行を超えて、何がどこにあるのか分からなくなります。
React の強みは、「画面を部品として切り出せること」です。
なので、「少し大きくなってきたな」と感じたら、積極的にコンポーネントに分割するクセをつけると、後から楽になります。
なぜ分けるのか
読みやすさと「考える量」を減らすため
コードを読むとき、人間の頭が一度に把握できる量には限界があります。
一つのコンポーネントが長くなりすぎると、
「ここは何をしているのか」
「どこがヘッダーで、どこがリストで、どこがボタンなのか」
が一瞬で分からなくなります。
例えば、トップページを考えたときに、
ヘッダー
メインコンテンツ
フッター
くらいに分けてしまえば、Page コンポーネントはかなり読みやすくなります。
export default function Page() {
return (
<main>
<Header />
<MainContent />
<Footer />
</main>
);
}
TSX詳細を知りたくなったら、それぞれのコンポーネントの中身を見に行けばいい。
これが「分割する最大のメリット」です。
読むときも、直すときも、「今はヘッダーだけ」「今はフッターだけ」と、考える範囲を絞れるので、作業が一気に楽になります。
変更に強くなるため
「ボタンのデザインを変えたい」「カードのレイアウトを変えたい」など、あとからの変更は必ず出てきます。
コンポーネントとして切り出しておけば、そのコンポーネントだけを直せば、使っている場所すべてに自動で反映されます。
逆に、毎回その場その場で HTML を書いてしまうと、
似たようなコードがあちこちにコピペされる
全部探して手で直さないといけない
1カ所だけ直し忘れてバグになる
という、しんどい未来が待っています。
親子構造の整理
「上が全体の流れ、下が細かいパーツ」という考え方
コンポーネントは、よく「親コンポーネント」と「子コンポーネント」という関係で語られます。
親が全体をまとめる役、子が細かい部分を担当する役、というイメージです。
例えば、次のような画面を想像してください。
ページ全体
その中にプロフィールカード
お知らせリスト
という構成です。
function ProfileCard() {
return (
<section>
<h2>プロフィール</h2>
<p>名前:太郎</p>
<p>職業:エンジニア</p>
</section>
);
}
function NewsList() {
return (
<section>
<h2>お知らせ</h2>
<ul>
<li>Next.js 入門講座 開始</li>
<li>React 基礎編 更新</li>
</ul>
</section>
);
}
export default function Page() {
return (
<main>
<ProfileCard />
<NewsList />
</main>
);
}
TSXここでの関係は、
Page が「親」
ProfileCard と NewsList が「子」
です。
親コンポーネントは、「このページには何が並ぶのか」を決めるディレクターの役割。
子コンポーネントは、「自分の担当部分をしっかり作る職人」というイメージです。
データの流れも整理される
親子構造を意識すると、データの流れも整理しやすくなります。
React では、データは基本的に「親から子へ props で渡す」一方向の流れなので、
ページ全体が持つ state は親に置く
表示に必要な部分だけを props で子に渡す
という構造になります。
例えば、ニュースの配列を Page で持っておき、それを NewsList に渡すイメージです。
function NewsList({ items }) {
return (
<section>
<h2>お知らせ</h2>
<ul>
{items.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</section>
);
}
export default function Page() {
const news = ["Next.js 入門講座 開始", "React 基礎編 更新"];
return (
<main>
<NewsList items={news} />
</main>
);
}
TSXこうすると、「データは親」「表示ロジックは子」という役割分担ができて、コードの見通しがよくなります。
再利用できる部品作成
「どこでも使える小さなパーツ」を意識する
コンポーネント分割の醍醐味は、「再利用できる部品」を作れることです。
特に、
ボタン
カード
入力フォーム
モーダル
のような UI 部品は、あちこちで同じようなものを使うので、コンポーネントとして切り出しておくと威力を発揮します。
例えば、共通のボタンコンポーネントを作ってみます。
type PrimaryButtonProps = {
children: React.ReactNode;
onClick?: () => void;
};
function PrimaryButton({ children, onClick }: PrimaryButtonProps) {
return (
<button
onClick={onClick}
style={{
backgroundColor: "#2563eb",
color: "white",
padding: "8px 16px",
borderRadius: "4px",
border: "none",
cursor: "pointer",
}}
>
{children}
</button>
);
}
TSXこれを使う側は、こうなります。
export default function Page() {
return (
<main>
<PrimaryButton onClick={() => alert("保存しました")}>
保存
</PrimaryButton>
<PrimaryButton onClick={() => alert("キャンセルしました")}>
キャンセル
</PrimaryButton>
</main>
);
}
TSXボタンの色や余白、角丸などのスタイルは PrimaryButton に集約されているので、デザインを変えたくなったらそこだけ直せばすべてに反映されます。
「具体的すぎない」コンポーネントにする工夫
再利用できるコンポーネントを作るコツは、名前や役割を少し抽象的にすることです。
例えば、
「保存ボタン」専用コンポーネントを作るより
「青いボタン」= PrimaryButton を作って、ラベルは children として渡す
ほうが、いろいろな場面で使い回せます。
同じように、
「ユーザー1人分のカード」より
「タイトルと説明文を表示するカード」
のように、「表示したいデータの中身」ではなく「見た目の枠組み」でコンポーネントを切り出すと、汎用性が上がります。
ディレクトリ構成
小さなところからコンポーネント用フォルダを作る
Next.js の App Router では app ディレクトリが基本ですが、その中に コンポーネント専用のフォルダを作るのが一般的です。
シンプルな構成例をイメージで書いてみます。
app/page.tsxcomponents/Header.tsxFooter.tsxPrimaryButton.tsx
page.tsx はページ単位のコンポーネント(URL に対応)components フォルダには「いろいろなページで使い回す部品」を入れる
という分け方です。
ページ専用のコンポーネント(そのページでしか使わないもの)は、
そのページ用のフォルダの中に components を作ることもあります。
例えば、/dashboard ページ専用の構成を考えると、
app/dashboard/page.tsxcomponents/StatsCard.tsxUserSummary.tsx
のような感じです。
ファイル名=コンポーネント名で揃える
ファイル名とコンポーネント名を揃えておくと、かなり分かりやすくなります。
Header.tsx → 中身のコンポーネント名は HeaderPrimaryButton.tsx → 中身は PrimaryButton
というように揃えておくと、
「このコンポーネントどこにあるんだっけ?」と迷いにくくなります。
まとめ(コンポーネント分割の考え方)
コンポーネントを分割する一番の理由は、読みやすさと変更のしやすさです。
親コンポーネントは「全体の流れとデータ」を管理し、子コンポーネントは「見た目や小さな挙動」を担当する構造にすると、頭の中がスッキリします。
再利用できる部品(ボタン・カード・フォームなど)を意識して切り出しておくと、デザイン変更や機能追加が圧倒的に楽になります。app/components のように「共通部品置き場」としてのフォルダを作り、ファイル名とコンポーネント名を揃えると、プロジェクト全体の整理もしやすくなります。
次のステップとしては、自分の page.tsx が少し長くなってきたところで、
ヘッダー部分
メインのカード部分
ボタン部分
をそれぞれ別コンポーネントに切り出してみると、「コンポーネント分割の前後でどれくらい読みやすさが変わるか」を実感できるはずです。
