このテーマのゴール
ここでやりたいのは、「カード」という“部品”を1つ作って、タイトルと本文だけ差し替えて何度も使えるようにすることです。
前の「名前だけ変えて挨拶」と同じ発想ですが、
もう少し“実際のアプリっぽい UI”に近づけた形で、props の使い方とコンポーネントの再利用を体で覚えていきます。
完成イメージを先に見てみる
「カード」コンポーネントの例
まずはゴールのコードを見てみましょう。
// components/Card.tsx
type CardProps = {
title: string;
body: string;
};
export function Card({ title, body }: CardProps) {
return (
<div
style={{
border: "1px solid #e5e7eb",
borderRadius: "8px",
padding: "12px 16px",
backgroundColor: "white",
boxShadow: "0 1px 3px rgba(15, 23, 42, 0.08)",
marginBottom: "12px",
}}
>
<h2 style={{ fontSize: "18px", marginBottom: "4px" }}>{title}</h2>
<p style={{ fontSize: "14px", color: "#4b5563" }}>{body}</p>
</div>
);
}
TSX// app/page.tsx
import { Card } from "./components/Card";
export default function Page() {
return (
<main
style={{
padding: "24px",
fontFamily: "system-ui, sans-serif",
backgroundColor: "#f3f4f6",
minHeight: "100vh",
}}
>
<h1 style={{ fontSize: "24px", marginBottom: "16px" }}>カードコンポーネントの例</h1>
<Card
title="お知らせ"
body="明日の勉強会は19時から開始します。Zoomリンクはメールをご確認ください。"
/>
<Card
title="新機能のご案内"
body="ダークモードが利用できるようになりました。設定画面から切り替えできます。"
/>
<Card
title="メンテナンス情報"
body="今週末の深夜にサーバーメンテナンスを予定しています。サービスが一時的にご利用いただけません。"
/>
</main>
);
}
TSX画面には、枠で囲まれたカードが3つ並び、
それぞれ「タイトル」と「本文」だけが違う状態になります。
props で「タイトル」と「本文」を受け取る仕組み
CardProps という“約束”を作る
まず、Card コンポーネントの定義部分を分解してみます。
type CardProps = {
title: string;
body: string;
};
TSXここでやっているのは、
「このカードは title と body という2つの文字列を受け取ります」
という“約束”を TypeScript で書いている、ということです。
これがあることで、
titleを渡し忘れたらエラーになるbodyに数字を渡そうとしたらエラーになる
つまり、「間違った使い方」をコンパイル時に止めてくれます。
コンポーネントの引数で props を受け取る
次に、この部分。
export function Card({ title, body }: CardProps) {
return (
...
);
}
TSXここは、
CardはCardProps型のオブジェクトを受け取る- そのオブジェクトから
titleとbodyを取り出して使う
という意味です。
イメージとしては、こう呼ばれている感じです。
Card({ title: "お知らせ", body: "明日の勉強会は…" });
Card({ title: "新機能のご案内", body: "ダークモードが…" });
TSXJSX では <Card title="お知らせ" body="…" /> と書きますが、
中身では「{ title: ..., body: ... } というオブジェクト」が渡されている、と考えると分かりやすいです。
同じカードを「中身だけ変えて」何度も使う
親コンポーネントから値を渡す
page.tsx 側の使い方をもう一度見てみます。
<Card
title="お知らせ"
body="明日の勉強会は19時から開始します。Zoomリンクはメールをご確認ください。"
/>
<Card
title="新機能のご案内"
body="ダークモードが利用できるようになりました。設定画面から切り替えできます。"
/>
TSXやっていることはとてもシンプルで、
- 1つ目のカードには「お知らせ」「明日の勉強会は…」という文字列を渡す
- 2つ目のカードには「新機能のご案内」「ダークモードが…」という文字列を渡す
というだけです。
コンポーネントの中身(枠線・余白・タイトルの位置など)は完全に同じ。
違うのは props として渡している title と body の値だけ。
これが「タイトルと本文を props で受け取るカードコンポーネント」の本質です。
配列+map で「カード一覧」にする
データを配列にまとめてから描画する
実際のアプリでは、「お知らせ」や「記事」などのデータを配列で持っておいて、
それを map でカードに変換することが多いです。
type Info = {
id: number;
title: string;
body: string;
};
const infos: Info[] = [
{
id: 1,
title: "お知らせ",
body: "明日の勉強会は19時から開始します。Zoomリンクはメールをご確認ください。",
},
{
id: 2,
title: "新機能のご案内",
body: "ダークモードが利用できるようになりました。設定画面から切り替えできます。",
},
{
id: 3,
title: "メンテナンス情報",
body: "今週末の深夜にサーバーメンテナンスを予定しています。",
},
];
export default function Page() {
return (
<main style={{ padding: "24px" }}>
<h1>お知らせ一覧</h1>
{infos.map((info) => (
<Card key={info.id} title={info.title} body={info.body} />
))}
</main>
);
}
TSXここでの大事なポイントは、
- 「データ(infos)」と「見た目(Card)」を分けて考えている
- データが増えても、配列に追加するだけでカードが増える
というところです。
カードコンポーネントは「見た目のテンプレート」、
配列は「中身のデータの集まり」──この役割分担ができると、一気にアプリっぽくなります。
まとめ:このカードコンポーネントからつかんでほしいこと
このテーマで本当に持ち帰ってほしいのは、次の感覚です。
コンポーネントは「枠(テンプレート)」で、props は「その枠に流し込む中身」
タイトルや本文のような“変わる部分”は props にして、見た目の構造はコンポーネントに閉じ込める
データを配列で持っておいて、map でカードに変換すると「一覧表示」が自然に書ける
ここが腑に落ちると、
- 記事カード
- 商品カード
- プロフィールカード
みたいな UI を、全部「同じ Card コンポーネント+違う props」で表現できるようになります。
もしよければ、この Card に「小さなフッターテキスト(例:投稿日)」を追加してみてください。footer みたいな props を増やしてみると、「props を増やしてコンポーネントの表現力を上げる」感覚がさらにつかめます。
