第25章:練習:childrenと型定義を使ったカード部品を作る。
この章では、 「中身をなんでも入れられるカード部品(Card コンポーネント)」 を作ってみます 🎉
ポイントはこの2つ 👇
childrenを使って、「カードの中身」を親コンポーネントから渡す- TypeScript で Props の型(とくに
children)をちゃんと定義する
1️⃣ ゴールのイメージ
最終的に、App.tsx からこんなふうに使えるカードを目指します ✨
<Card title="今日やること">
<ul>
<li>React の勉強 💻</li>
<li>課題をちょっと進める ✏️</li>
<li>推しの配信を見る 🎧</li>
</ul>
</Card>
<Card title="メモ">
<p>明日は友だちとランチ 🍝</p>
</Card>
Card 側は、「枠」と「タイトルだけ」決めておいて、
中身 (<ul>... や <p>...) はぜんぶ children におまかせ、というスタイルです 💡
2️⃣ ファイルを用意しよう 🗂️
VS Code で、プロジェクトの src フォルダの中に
src/components/Card.tsx
というファイルを新しく作ってください 📁
(components フォルダがまだなければ作ってOK!)
3️⃣ Props の型を考える時間 💭
Card コンポーネントが欲しい情報はこの2つだけです。
title: カードのタイトル(文字列)children: カードの中に入れる「中身」
children の型は、React では ReactNode を使っておくのが定番です。
文字列・数値・別のコンポーネント・配列・null など、
React がレンダリングできるほとんど全部を受け取れる便利な型です。(Zenn)
まずは Card.tsx に、型定義だけ書いてみましょう ✍️
// src/components/Card.tsx
import type { ReactNode } from "react";
type CardProps = {
title: string;
children: ReactNode;
};
ここまでで、
CardPropsという Props の形(型)childrenという名前のプロパティがあり、- その型は
ReactNode
という準備ができました 🧩
4️⃣ Card コンポーネント本体を書く ✨
次に、Card コンポーネントそのものを書いていきます。
この章ではまだ 「Props の分割代入」(({ title }) って書くやつ)は次の章でやるので、
いったん素直に props.title / props.children と書きます 👀
// src/components/Card.tsx
import type { ReactNode } from "react";
type CardProps = {
title: string;
children: ReactNode;
};
export const Card = (props: CardProps) => {
return (
<section className="card">
<h2 className="cardTitle">{props.title}</h2>
<div className="cardBody">{props.children}</div>
</section>
);
};
ここでやっていること 📝
CardはCardProps型のpropsを受け取る関数として定義<h2>の中でprops.titleを表示<div className="cardBody">の中にprops.childrenをそのまま表示export const Card = ...にしておくことで、 別ファイル(App.tsxなど)からimportして使えるようになる
children は 特別な名前の Props で、
親コンポーネントが <Card>...ここ...</Card> の「...ここ...」の部分を渡してくれます 🌟(LogRocket Blog)
5️⃣ ちょっとだけ見た目を整える(お好みで)🎨
まだスタイリングの章は後でやりますが、 「なんにも装飾がないと味気ない…😢」という人向けに、 とりあえずサクッと簡単な CSS だけ書いておきます。
src/index.css など、全体に効いている CSS ファイルに、次を足してみてください。
.card {
border: 1px solid #ddd;
border-radius: 12px;
padding: 16px;
margin-bottom: 16px;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
}
.cardTitle {
margin: 0 0 8px;
font-size: 1.1rem;
font-weight: 600;
}
.cardBody {
font-size: 0.95rem;
line-height: 1.6;
}
これで、ちょっと「それっぽいカード」になります ✨ (デザインはあとでいくらでも変えられるので、今は「動くこと」が最優先でOK!)
6️⃣ App.tsx から使ってみよう 🚀
今度は App.tsx で、作った Card を実際に使ってみます。
src/App.tsx を開いて、こんな感じに書き換えてみてください。
⚠️ すでに何か書いてある場合は、いったん全部消してから貼ってOKです。
// src/App.tsx
import "./App.css";
import { Card } from "./components/Card";
function App() {
return (
<main style={{ maxWidth: 480, margin: "24px auto", padding: "0 16px" }}>
<h1>カード部品の練習 ✨</h1>
<Card title="今日やること">
<ul>
<li>React の勉強 💻</li>
<li>大学の課題 ✏️</li>
<li>推しチェック 👀</li>
</ul>
</Card>
<Card title="メモ">
<p>明日はカフェで勉強会 ☕️📚</p>
</Card>
<Card title="ひとこと">
<p>React は慣れてくるとめっちゃ楽しいよ〜 ✨</p>
</Card>
</main>
);
}
export default App;
動作チェック ✅
-
すでに
npm run devを動かしている場合 → ブラウザをリロード 🔁 -
まだなら、ターミナルで
npm run devを実行して、表示された URL(たぶん
http://localhost:5173みたいなやつ)をブラウザで開く
カードが 3 つ並んでいれば成功です 🎉
7️⃣ children を使うと何がうれしいの?🤔
今回の Card コンポーネントは、中身をぜんぶ props.children に任せています。
<div className="cardBody">{props.children}</div>
このおかげで、親コンポーネント側では
<ul>...</ul>を入れてもいいし<p>...</p>でもいいし- もっと複雑なレイアウトを入れてもいいし
- なんなら別のコンポーネントを丸ごと入れてもOK
という 「めちゃ自由度の高い入れ物」 が作れます 📦✨
children の型を ReactNode にしてあるので、
React が表示できるほとんど全部を受け取れる、
万能コンテナ みたいなカードになっているわけです 🌈(Zenn)
8️⃣ ミニ応用:children を入れ忘れたらどうなる?🧐
今回の型定義では
children: ReactNode;
と書いているので、children は 必須 です。
もし App.tsx でこんなふうに書くと…
// ❌ children なしの Card
<Card title="からっぽのカード" />
TypeScript がちゃんとエラーを出してくれます 🧠✨
"Card" 型には "children" が必要ですよ〜
みたいなメッセージが出たら、「あ、children 渡し忘れてる!」と気づけるので安心ですね 🥰
※ もし「中身がないカードもアリ」にしたくなったら、
children?: ReactNode;(? をつける)にすると、「あってもなくてもOK」 になります。
9️⃣ この章のまとめ 🌸
childrenは、<Card>ここ</Card>の「ここ」の部分を受け取る 特別な Propschildrenの型にはReactNodeを使うのが定番 → 文字列・数値・別のコンポーネントなど、いろいろ受け取れて便利 🎁(LogRocket Blog)- 今回は
CardPropsを自分で定義して、titleとchildrenを型付きで受け取るコンポーネントを作った childrenを使うことで、 「枠(見た目)は Card 側で決めて、中身は親側が自由に決める」 というパターンが実現できた✨
🔟 おまけ練習(時間があれば)💪
時間や気力に余裕があれば、こんなアレンジもやってみてね 🧪
-
CardにfooterText: stringという Props を追加して、- カードのいちばん下に小さくフッター文字を出す
- 例:
footerText="最終更新: 2025-11-26"みたいな感じ
-
childrenの中で、絵文字をいっぱい使ってみる → テキストだけのカードと、リッチなカードの見た目の違いを楽しんでみてね ✨ -
childrenをわざと<strong>だけにしてみる、<img>を入れてみる など、 「いろんな中身」がちゃんと表示されるか試してみる 🔍
次の 第26章 では、
今回書いた props.title / props.children を、
もっとスッキリ書けるように 「Props の分割代入」 にチャレンジしていきます 💖