JSXの書き方:React開発の第一歩

2025-08-07

はじめに

JSX(JavaScript XML)はReactの核となる構文で、JavaScript内にHTMLのようなマークアップを直接記述できるようにします。これにより、UIの構造を直感的に表現できるようになります。Reactを学び始めるにあたり、JSXの基本をしっかり理解することは非常に重要です。

JSXの基本概念

JSXはJavaScriptの構文拡張で、HTMLのようにUIを記述できる。式を埋め込める柔軟性があり、Reactでの画面構築を直感的かつ効率的に行えます。

JSXとは何か?

JSXはJavaScriptの構文拡張で、以下のような特徴があります。

  • HTMLに似た構文でUIを記述できる
  • 実際にはJavaScriptに変換(トランスパイル)されて実行される
  • React要素(React Element)を生成する
const element = <h1>Hello, world!</h1>;

この例では、見た目はHTMLのようですが、実際にはJavaScriptのコードです。Babelなどのトランスパイラがこのコードを通常のJavaScriptに変換します。

JSXがなぜ必要なのか?

JSXが必要とされる理由は、まずUIの構造をコード上で直感的に理解できるという視覚的なわかりやすさにあります。また、HTMLとJavaScriptを分離せずに一体として記述できるため、開発効率の向上にもつながります。さらに、Reactの仮想DOMと密接に連携することで、Reactの機能を最大限に活用できる点も大きな利点です。

JSXの基本的な書き方

JSXはHTMLに似た記法で要素を記述し、JavaScriptの式は{}で埋め込む。classNameなど独自属性を使い、要素は単一のルートで囲む必要があります。

基本的な要素のレンダリング

最も単純なJSXの例を見てみましょう。

const greeting = <h1>こんにちは、Reactの世界へ!</h1>;

ReactDOM.render(
  greeting,
  document.getElementById('root')
);

このコードは、「こんにちは、Reactの世界へ!」という見出しを表示します。

JSXの構文規則

  1. 単一のルート要素

JSXは常に1つのルート要素で囲む必要があります。

// 正しい例
const element = (
  <div>
    <h1>タイトル</h1>
    <p>本文</p>
  </div>
);

// 誤った例(複数のトップレベル要素)
const element = (
  <h1>タイトル</h1>
  <p>本文</p>
);

React 16.2以降ではFragment(<>...</>)を使用して不要なdivを避けられます。

   const element = (
     <>
       <h1>タイトル</h1>
       <p>本文</p>
     </>
   );
  1. タグの閉じ忘れに注意

HTMLとは異なり、JSXではすべてのタグを明示的に閉じる必要があります。

  // 正しい例
  <img src="image.jpg" alt="説明" />
  <br />
  <div></div>

  // 誤った例
  <img src="image.jpg" alt="説明">
  <br>
  1. classNameの使用

HTMLのclass属性は、JSXではclassNameとして記述します。

  // 正しい例
  <div className="container">...</div>

  // 誤った例
  <div class="container">...</div>
  1. インラインスタイル

スタイルをオブジェクト形式で記述します。プロパティ名はキャメルケースになります。

const style = {
  color: 'blue',
  fontSize: '20px', // ハイフン付きプロパティ名はキャメルケースに
  backgroundColor: '#f0f0f0' // 背景色もキャメルケース
};

<div style={style}>スタイル付き要素</div>

// または直接記述
<div style={{ color: 'red', padding: '10px' }}>インラインスタイル</div>

JSX内でのJavaScript式の埋め込み

JSX内でJavaScriptの式を実行するには、中括弧{}を使用します。

変数の表示

JSXではHTML風の記述の中に、{}を使ってJavaScriptの変数や式を埋め込めるため、動的に内容を表示できるのが特徴です。

const name = '山田太郎';
const element = <p>こんにちは、{name}さん!</p>;

式の評価

JSXでは{}内にJavaScriptの式を記述でき、変数だけでなく計算結果もそのまま画面に動的に表示できるのが特徴です。

const a = 5;
const b = 10;
const element = (
  <p>
    {a} + {b} = {a + b}
  </p>
);
// 結果: "5 + 10 = 15" と表示

関数の実行

JSXでは{}内に関数呼び出しも記述でき、関数の戻り値を使って表示内容を動的に生成できるのが特徴です。

function formatName(user) {
  return `${user.lastName} ${user.firstName}`;
}

const user = {
  firstName: '太郎',
  lastName: '山田'
};

const element = (
  <p>こんにちは、{formatName(user)}さん!</p>
);
// 結果: "こんにちは、山田 太郎さん!" と表示

条件付きレンダリング

JSX内でif文は直接使えませんが、三項演算子や論理AND演算子を使用できます。

const isLoggedIn = true;

const element = (
  <div>
    {isLoggedIn ? (
      <p>ようこそ、ユーザーさん!</p>
    ) : (
      <p>ログインしてください</p>
    )}
  </div>
);

または&&を使った条件式により、条件が真のときだけ要素を表示する「条件付きレンダリング」が簡単に実現できるのが特徴です。

const unreadMessages = ['メッセージ1', 'メッセージ2'];

const element = (
  <div>
    <h1>メッセージボックス</h1>
    {unreadMessages.length > 0 && (
      <p>未読メッセージが{unreadMessages.length}件あります</p>
    )}
  </div>
);

JSXでのリストレンダリング

配列をリストとして表示するには、map()メソッドを使用します。

const numbers = [1, 2, 3, 4, 5];

const listItems = numbers.map((number) => (
  <li key={number.toString()}>{number}</li>
));

const element = <ul>{listItems}</ul>;

key属性の重要性

リストをレンダリングする際、各項目に一意のkey属性を指定する必要があります。これによりReactはどの項目が変更、追加、削除されたかを効率的に判断できます。

const todos = [
  { id: 1, text: 'Reactを学ぶ' },
  { id: 2, text: 'プロジェクトを作成' },
  { id: 3, text: 'デプロイする' }
];

const todoList = todos.map((todo) => (
  <li key={todo.id}>{todo.text}</li>
));

JSXの注意点

JSXでは要素は必ず1つのルートで囲む必要があります。また、classNameなどHTMLと異なる記法に注意し、式は{}内に記述する点にも気をつけましょう。

HTMLとの違い

  1. 属性名の違い
  • classclassName
  • forhtmlFor
  • tabindextabIndex
  1. スタイルの記述方法

CSSプロパティ名はキャメルケースで、値は文字列として記述します。

<div style={{ marginTop: '10px', paddingLeft: '20px' }}>...</div>

インジェクション攻撃の防止

JSXは自動的にXSS(クロスサイトスクリプティング)攻撃を防ぎます。すべての値はレンダー前にエスケープされます。

const userInput = '<script>alert("危険!")</script>';

// 安全 - スクリプトは実行されず、テキストとして表示される
const element = <div>{userInput}</div>;

コメントの書き方

JSX内でのコメントは特殊な構文です。HTMLのように直接コメントを書くのではなく、{/* コメント */}の形式で記述します。また、{}内であれば通常のJavaScriptコメント(///* */)も使用できます。

const element = (
  <div>
    {/* これはJSX内のコメントです */}
    <h1>タイトル</h1>
    {
      // これも有効なコメント
    }
  </div>
);

実践的なJSXの例

シンプルなプロフィールカード

オブジェクトのデータをもとにプロフィールカードを表示するコンポーネントです。

{}を使って名前や年齢などのデータを埋め込み、map関数で趣味の配列をリスト表示しています。また、key属性で各要素を識別し、&&を使った条件付きレンダリングにより、プレミアム会員の場合のみ特定の表示を行っています。さらに、classNamestyleを使って見た目の装飾も行っているのが特徴です。

const profile = {
  name: '佐藤花子',
  age: 28,
  hobbies: ['読書', '旅行', '写真'],
  isPremium: true
};

const ProfileCard = () => (
  <div className="profile-card" style={{ border: '1px solid #ccc', padding: '20px', borderRadius: '8px' }}>
    <h2>{profile.name}</h2>
    <p>年齢: {profile.age}歳</p>
    <div>
      <h3>趣味:</h3>
      <ul>
        {profile.hobbies.map((hobby, index) => (
          <li key={index}>{hobby}</li>
        ))}
      </ul>
    </div>
    {profile.isPremium && <p className="premium">プレミアム会員</p>}
  </div>
);

天気表示コンポーネント

天気情報を表示するコンポーネントです。オブジェクトのデータから都市名や現在の気温、天気の状態を{}で埋め込んで表示し、map関数を使って週間予報の配列を繰り返し描画しています。各要素にはkeyを設定し、classNameでスタイル指定を行うことで、構造的で見やすいUIを実現しているのが特徴です。

const weatherData = {
  city: '東京',
  temp: 22,
  condition: '晴れ',
  forecast: [
    { day: '月', temp: 22 },
    { day: '火', temp: 24 },
    { day: '水', temp: 19 }
  ]
};

const WeatherDisplay = () => (
  <div className="weather">
    <h1>{weatherData.city}の天気</h1>
    <p>現在の気温: {weatherData.temp}°C</p>
    <p>状態: {weatherData.condition}</p>

    <h2>週間予報</h2>
    <div className="forecast">
      {weatherData.forecast.map((dayData, index) => (
        <div key={index} className="forecast-day">
          <p>{dayData.day}曜日</p>
          <p>{dayData.temp}°C</p>
        </div>
      ))}
    </div>
  </div>
);

JSXのよくある間違いとデバッグ

JSXではタグの閉じ忘れや単一ルート未対応、classとclassNameの混同がよくある間違いです。エラー文を確認し、該当箇所を特定して修正することが重要です。

よくあるエラーと解決方法

  1. Unexpected tokenエラー
  • 原因:HTMLタグが正しく閉じられていない
  • 解決法:すべてのタグを閉じる
  1. Adjacent JSX elementsエラー
  • 原因:複数のトップレベル要素がある
  • 解決法:Fragmentまたはdivで囲む
  1. ‘className’ is not definedエラー
  • 原因:classを使用している
  • 解決法:classNameに変更

JSXのデバッグ方法

  1. コンソールログ

次はelementというReact要素の中身をコンソールに出力し、どのような構造になっているかを確認するためのデバッグ処理です。

   console.log(element); // React要素を確認
  1. Babel REPL

JSXがどのようなJavaScriptに変換されるか確認できます。(https://babeljs.io/repl)

  1. React Developer Tools

Chrome拡張をインストールして、Reactコンポーネントツリーを検査できます。

まとめ

JSXは、UIを直感的に記述できるJavaScriptの構文拡張であり、React開発の基礎となる技術です。見た目はHTMLに似ていますが、classNameの使用やスタイル記述方法などいくつかの違いがあります。また、{}を使ってJavaScriptの式を埋め込める点が特徴で、リストを描画する際にはkeyプロパティが必要です。さらに、要素は常に単一のルートで囲む必要があり、その際にはFragmentが便利に使えます。加えて、JSXは自動的にエスケープ処理が行われるため、XSS攻撃への対策も施されています。最初は慣れが必要ですが、一度理解すれば非常に強力であり、次のステップではこれを用いたコンポーネント作成へと進みます。

🟢 初級問題(問題1〜3)

JSXの基本構文を確認する問題です。HTMLとJSXの違い、式の埋め込み、属性の書き方を練習します。

問題1:JSXの基本要素を修正しよう

【問題】
以下のコードにはJSXの構文エラーが3箇所あります。すべて修正してください。

ProfileCard.js(もしくはjsx)を作成してApp.jsに読み込ませてください。

const ProfileCard = () => (
  <div class="profile">
    <img src="avatar.png" alt="プロフィール画像">
    <h2>田中太郎</h2>
    <p>エンジニア</p>
  </div>
  <p>よろしくお願いします</p>
);

【エラーの内容】

  • HTMLの class 属性をそのまま使っている
  • <img> タグが閉じられていない
  • トップレベルの要素が2つある

【修正後の期待する動作】
エラーなくレンダリングされ、プロフィール画像・名前・肩書き・挨拶文が1つの要素内に収まっている。


問題2:変数と式を埋め込もう

【問題】
以下の変数を使って、期待する出力と同じHTMLを生成するJSXを完成させてください。____ の部分を埋めてください。

const productName = "ワイヤレスイヤホン";
const price = 4980;
const stock = 3;
const taxRate = 0.1;

const ProductInfo = () => (
  <div className="product">
    <h2>商品名:____</h2>
    <p>価格:____円(税込 ____円)</p>
    <p>残り____点</p>
  </div>
);

【期待する表示】

商品名:ワイヤレスイヤホン
価格:4980円(税込 5478円)
残り3点

※ 税込価格は price * (1 + taxRate) で計算し、整数で表示すること。


問題3:条件によって表示を切り替えよう

【問題】
以下の user オブジェクトを使い、ログイン状態(isLoggedIn)に応じて表示を切り替えるJSXを作成してください。

const user = {
  name: "鈴木花子",
  isLoggedIn: true,   // false に変えても動作を確認すること
  unreadCount: 5,
};

【条件】

  • isLoggedIntrue のとき:"鈴木花子さん、ようこそ!" と表示し、unreadCount が1以上なら "未読メッセージが5件あります" を追加表示する
  • isLoggedInfalse のとき:"ログインしてください" とだけ表示する
  • 三項演算子と && 演算子を使うこと(if 文は使わない)

【期待する表示(isLoggedIn: true の場合)】

鈴木花子さん、ようこそ!
未読メッセージが5件あります

🟡 中級問題(問題4〜9)

リストのレンダリング・インラインスタイル・複合的なJSX式など、実践的な場面で頻出するパターンに取り組みます。

問題4:配列をリスト表示しよう

【問題】
以下の members 配列を使って、チームメンバーの一覧を表示するJSXを作成してください。

const members = [
  { id: 1, name: "田中太郎",   role: "フロントエンド", active: true  },
  { id: 2, name: "鈴木花子",   role: "バックエンド",   active: true  },
  { id: 3, name: "佐藤次郎",   role: "デザイナー",     active: false },
  { id: 4, name: "山田三郎",   role: "インフラ",       active: true  },
];

【条件】

  • map() を使って各メンバーを <li> でレンダリングする
  • <li> には必ず key 属性を設定する(id を使うこと)
  • active: false のメンバーには (休止中) を名前の後ろに追記する(&& 演算子を使うこと)
  • 表示形式:田中太郎 ― フロントエンド

【期待する表示】

• 田中太郎 ― フロントエンド
• 鈴木花子 ― バックエンド
• 佐藤次郎(休止中) ― デザイナー
• 山田三郎 ― インフラ

問題5:インラインスタイルを動的に切り替えよう

【問題】
以下の tasks 配列を使い、完了済みタスクにだけ取り消し線と灰色のスタイルを適用したリストを作成してください。

const tasks = [
  { id: 1, text: "要件定義を読む",         done: true  },
  { id: 2, text: "環境構築をする",         done: true  },
  { id: 3, text: "Reactの基本を学ぶ",     done: false },
  { id: 4, text: "JSXの練習問題を解く",   done: false },
];

【条件】

  • インラインスタイルを style 属性でオブジェクトとして渡すこと
  • done: true のとき:textDecoration: "line-through"color: "#aaa" を適用
  • done: false のとき:スタイルなし(空オブジェクト {} でもよい)
  • 三項演算子でスタイルを切り替えること

問題6:テーブルをJSXで作成しよう

【問題】
以下のデータを使って、成績一覧テーブルをJSXで作成してください。

const grades = [
  { id: 1, name: "田中太郎", math: 88, english: 72, science: 95 },
  { id: 2, name: "鈴木花子", math: 76, english: 91, science: 68 },
  { id: 3, name: "佐藤次郎", math: 95, english: 85, science: 80 },
];

【条件】

  • ヘッダー行:名前 / 数学 / 英語 / 理科 / 合計
  • 各行の合計点は math + english + science で計算してJSX内で表示する
  • 合計点が250以上の行には className="high-score" を追加する
  • <tr>key 属性を設定すること

【期待する表示】

名前        数学  英語  理科  合計
田中太郎     88   72   95   255  ← high-score
鈴木花子     76   91   68   235
佐藤次郎     95   85   80   260  ← high-score

問題7:ネストしたデータを展開して表示しよう

【問題】
以下のネストしたデータ構造を使って、カテゴリごとにメニュー項目を表示するJSXを作成してください。

const menu = [
  {
    id: 1,
    category: "ドリンク",
    items: ["コーヒー", "紅茶", "オレンジジュース"],
  },
  {
    id: 2,
    category: "フード",
    items: ["サンドイッチ", "スコーン", "チーズケーキ"],
  },
  {
    id: 3,
    category: "セット",
    items: ["Aセット(ドリンク+フード)", "Bセット(全品)"],
  },
];

【条件】

  • カテゴリを <h3>、各アイテムを <li> で表示する
  • 外側の map()(カテゴリ)・内側の map()(アイテム)の両方に key を設定すること
  • 内側の key はアイテムの文字列そのものを使ってよい

【期待する表示】

ドリンク
  • コーヒー
  • 紅茶
  • オレンジジュース
フード
  • サンドイッチ
  ...

問題8:JSXで関数を呼び出して表示を整えよう

【問題】
以下のデータと関数を使って、天気予報カードをJSXで作成してください。

const forecast = [
  { day: "月", temp: 28, condition: "sunny"  },
  { day: "火", temp: 22, condition: "cloudy" },
  { day: "水", temp: 18, condition: "rainy"  },
  { day: "木", temp: 25, condition: "sunny"  },
];

function formatCondition(condition) {
  const map = { sunny: "☀️ 晴れ", cloudy: "☁️ 曇り", rainy: "🌧️ 雨" };
  return map[condition] ?? "不明";
}

function getTempColor(temp) {
  if (temp >= 27) return "red";
  if (temp >= 20) return "orange";
  return "blue";
}

【条件】

  • 各カードを <div className="card"> で作成し、map() で並べる
  • formatCondition(){} 内から呼び出して天気を表示する
  • 気温は getTempColor() の戻り値をインラインスタイルの color に渡して色付きで表示する

【期待する表示(月曜日のカード)】

月曜日
☀️ 晴れ
28°C  ← 赤色

問題9:コメントとFragment を正しく使おう

【問題】
以下のコードには4つの問題があります。すべて修正してください。

const Dashboard = () => (
  <div>
    <!-- 統計情報セクション -->
    <section>
      <h2>統計情報</h2>
      <p>今月の売上: {sales}円</p>
    </section>

    // 通知セクション
    <section>
      <h2>通知</h2>
      {notifications.map((n) => (
        <p>{n.message}</p>
      ))}
    </section>
  </div>
);

【変数の前提】

const sales = 128000;
const notifications = [
  { id: 1, message: "新しいコメントがあります" },
  { id: 2, message: "注文が完了しました" },
];

【問題箇所のヒント】

  • JSX内のコメントの書き方が2箇所間違っている
  • map()key 属性が抜けている
  • sales が未定義のまま使われている(変数定義を追加すること)

🔴 上級問題(問題10〜12)

複合的なデータ処理とJSXの組み合わせ、パフォーマンスを意識した書き方など、実際の開発に近いシナリオに挑戦します。

問題10:フィルタリング結果をJSXで表示しよう

【問題】
以下の商品データに対し、filter()map() を組み合わせて特定条件の商品だけを表示するJSXを作成してください。

const products = [
  { id: 1, name: "ノートPC",         category: "電子機器", price: 89800, inStock: true  },
  { id: 2, name: "ワイヤレスマウス", category: "電子機器", price: 3200,  inStock: false },
  { id: 3, name: "デスクチェア",     category: "家具",     price: 45000, inStock: true  },
  { id: 4, name: "モニター",         category: "電子機器", price: 32000, inStock: true  },
  { id: 5, name: "本棚",             category: "家具",     price: 18000, inStock: false },
  { id: 6, name: "キーボード",       category: "電子機器", price: 12000, inStock: true  },
];

【条件】

  • category === "電子機器" かつ inStock === true の商品だけ表示する
  • 表示内容:商品名・価格(カンマ区切り)・在庫状況
  • 価格のカンマ区切りは toLocaleString() を使うこと
  • 該当する商品が0件の場合は "条件に合う商品はありません" と表示する

【期待する表示】

ノートPC — ¥89,800 — 在庫あり
モニター — ¥32,000 — 在庫あり
キーボード — ¥12,000 — 在庫あり

問題11:ソート済みデータをJSXで表示しよう

【問題】
以下の試験結果データを合計点の降順にソートし、順位付きで表示するJSXを作成してください。

const results = [
  { id: 1, name: "田中太郎", scores: { math: 80, english: 70, science: 90 } },
  { id: 2, name: "鈴木花子", scores: { math: 95, english: 88, science: 76 } },
  { id: 3, name: "佐藤次郎", scores: { math: 60, english: 92, science: 85 } },
  { id: 4, name: "山田三郎", scores: { math: 88, english: 75, science: 95 } },
];

【条件】

  • 各生徒の合計点を計算して降順にソートする(元の配列を変更しないよう [...results] でコピーすること)
  • 表示:1位 山田三郎(合計: 258点) のように順位・名前・合計点を表示する
  • 1位の生徒には className="first-place" を追加する
  • key には元データの id を使うこと

【期待する表示】

1位 山田三郎(合計: 258点)← first-place クラス付き
2位 鈴木花子(合計: 259点)
3位 佐藤次郎(合計: 237点)
4位 田中太郎(合計: 240点)

問題12:複合的なJSXを組み立てよう

【問題】
以下のSNSフィード風データを使って、投稿カードのJSXを作成してください。

const posts = [
  {
    id: 1,
    user: { name: "田中太郎", avatar: "👨" },
    content: "Reactの勉強を始めました!JSXって面白いですね。",
    likes: 12,
    comments: ["いいね!", "頑張ってください"],
    pinned: true,
  },
  {
    id: 2,
    user: { name: "鈴木花子", avatar: "👩" },
    content: "今日のランチは美味しかった🍜",
    likes: 5,
    comments: [],
    pinned: false,
  },
  {
    id: 3,
    user: { name: "佐藤次郎", avatar: "🧑" },
    content: "新しいプロジェクトのキックオフ!チーム一丸で頑張ります。",
    likes: 28,
    comments: ["応援しています!"],
    pinned: false,
  },
];

【条件】

  • pinned: true の投稿は先頭に表示し、📌 ピン留め バッジを表示する
  • 各カードにアバター(絵文字)・ユーザー名・本文・いいね数を表示する
  • コメントが1件以上あれば "コメント〇件"、0件なら "コメントなし" と表示する
  • いいね数が20以上の投稿には className="popular" を追加する
  • 表示順:ピン留め投稿を先頭に、残りは元の順序のまま

📘 解説(全12問)

解説1:JSXの基本要素を修正しよう

【解答例】

// App.js
import ProfileCard from './ProfileCard';

function App() {
  return <ProfileCard />;
}

// ProfileCard.js
const ProfileCard = () => (
  <>
    <div className="profile">
      <img src="avatar.png" alt="プロフィール画像" />
      <h2>田中太郎</h2>
      <p>エンジニア</p>
    </div>
    <p>よろしくお願いします</p>
  </>
);

【解説】

  • classclassName:JSXではHTML属性 classclassName と書く
  • <img><img />:JSXではすべてのタグを明示的に閉じる必要がある
  • 複数のトップレベル要素は Fragment(<>...</>)で囲む

解説2:変数と式を埋め込もう

【解答例】

const ProductInfo = () => (
  <div className="product">
    <h2>商品名:{productName}</h2>
    <p>価格:{price}円(税込 {Math.floor(price * (1 + taxRate))}円)</p>
    <p>残り{stock}点</p>
  </div>
);

【解説】

  • 変数は {変数名} の形式でJSX内に埋め込む
  • {} の中にはJavaScriptの式(計算・関数呼び出しなど)をそのまま書ける
  • Math.floor() を使って小数を切り捨て、整数で表示する

解説3:条件によって表示を切り替えよう

【解答例】

const Greeting = () => (
  <div>
    {user.isLoggedIn ? (
      <>
        <p>{user.name}さん、ようこそ!</p>
        {user.unreadCount > 0 && (
          <p>未読メッセージが{user.unreadCount}件あります</p>
        )}
      </>
    ) : (
      <p>ログインしてください</p>
    )}
  </div>
);

【解説】

  • 三項演算子 条件 ? 真の場合 : 偽の場合 でログイン状態を切り替える
  • && 演算子は「左辺が真のときだけ右辺を表示する」ショートサーキット評価
  • 三項演算子の中で複数要素を返すときも Fragment で囲む

解説4:配列をリスト表示しよう

【解答例】

const MemberList = () => (
  <ul>
    {members.map((member) => (
      <li key={member.id}>
        {member.name}{!member.active && "(休止中)"} ― {member.role}
      </li>
    ))}
  </ul>
);

【解説】

  • key には配列インデックスではなく、一意のIDを使うのがベストプラクティス
  • !member.active && "(休止中)"activefalse のときだけ文字列を表示できる
  • JSX内ではテキストとJavaScript式を隣接して書くことができる

解説5:インラインスタイルを動的に切り替えよう

【解答例】

const TaskList = () => (
  <ul>
    {tasks.map((task) => (
      <li
        key={task.id}
        style={
          task.done
            ? { textDecoration: "line-through", color: "#aaa" }
            : {}
        }
      >
        {task.text}
      </li>
    ))}
  </ul>
);

【解説】

  • JSXの style 属性にはCSSプロパティをキャメルケースで書いたオブジェクトを渡す
  • style={{ ... }} の二重波括弧は「JSX式の {}」と「スタイルオブジェクトの {}」が重なったもの
  • スタイルオブジェクトを変数として先に定義しておくと読みやすくなる

解説6:テーブルをJSXで作成しよう

【解答例】

const GradeTable = () => (
  <table>
    <thead>
      <tr>
        <th>名前</th>
        <th>数学</th>
        <th>英語</th>
        <th>理科</th>
        <th>合計</th>
      </tr>
    </thead>
    <tbody>
      {grades.map((g) => {
        const total = g.math + g.english + g.science;
        return (
          <tr key={g.id} className={total >= 250 ? "high-score" : ""}>
            <td>{g.name}</td>
            <td>{g.math}</td>
            <td>{g.english}</td>
            <td>{g.science}</td>
            <td>{total}</td>
          </tr>
        );
      })}
    </tbody>
  </table>
);

【解説】

  • map() のコールバック内で変数(total)を定義したいときは、アロー関数を () => () から () => {} に変え、return を明示する
  • className にも三項演算子で条件付きクラスを渡せる
  • テーブル要素(theadtbodytr)もすべて通常のJSX要素として書ける

解説7:ネストしたデータを展開して表示しよう

【解答例】

const MenuList = () => (
  <div>
    {menu.map((section) => (
      <div key={section.id}>
        <h3>{section.category}</h3>
        <ul>
          {section.items.map((item) => (
            <li key={item}>{item}</li>
          ))}
        </ul>
      </div>
    ))}
  </div>
);

【解説】

  • map() はネストして使える。外側のループでカテゴリを、内側のループでアイテムを処理する
  • 内側の key はリスト内で一意であればよいため、ユニークな文字列をそのまま使える
  • 各カテゴリのブロックをラップする <div key={section.id}> を忘れずに追加する

解説8:JSXで関数を呼び出して表示を整えよう

【解答例】

const ForecastCards = () => (
  <div className="forecast">
    {forecast.map((day) => (
      <div key={day.day} className="card">
        <h3>{day.day}曜日</h3>
        <p>{formatCondition(day.condition)}</p>
        <p style={{ color: getTempColor(day.temp), fontWeight: "bold" }}>
          {day.temp}°C
        </p>
      </div>
    ))}
  </div>
);

【解説】

  • JSXの {} 内から通常のJavaScript関数を呼び出せる
  • 関数の戻り値を style オブジェクトの値として直接使うことで、動的なスタイルが実現できる
  • ロジックを関数に切り出すことでJSXをシンプルに保てる(関心の分離)

解説9:コメントとFragment を正しく使おう

【解答例】

const sales = 128000;
const notifications = [
  { id: 1, message: "新しいコメントがあります" },
  { id: 2, message: "注文が完了しました" },
];

const Dashboard = () => (
  <div>
    {/* 統計情報セクション */}
    <section>
      <h2>統計情報</h2>
      <p>今月の売上: {sales}円</p>
    </section>

    {/* 通知セクション */}
    <section>
      <h2>通知</h2>
      {notifications.map((n) => (
        <p key={n.id}>{n.message}</p>
      ))}
    </section>
  </div>
);

【解説】

  • JSX内のコメントは {/* コメント */} の形式のみ有効。HTMLの <!-- -->// はJSX内では使えない
  • map() でレンダリングする要素には必ず key を設定する
  • JSXより前に使用する変数はすべてスコープ内で定義しておく必要がある

解説10:フィルタリング結果をJSXで表示しよう

【解答例】

const FilteredProducts = () => {
  const filtered = products.filter(
    (p) => p.category === "電子機器" && p.inStock
  );

  return (
    <div>
      {filtered.length === 0 ? (
        <p>条件に合う商品はありません</p>
      ) : (
        <ul>
          {filtered.map((p) => (
            <li key={p.id}>
              {p.name} — ¥{p.price.toLocaleString()} — 在庫あり
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

【解説】

  • filter() の結果を変数に入れてから map() すると、JSXがシンプルで読みやすくなる
  • アロー関数コンポーネントで変数を定義したいときは () => ()() => { return (...) } に変える
  • 件数チェック(length === 0)と一覧表示を三項演算子で切り替えるパターンは頻出

解説11:ソート済みデータをJSXで表示しよう

【解答例】

const RankingList = () => {
  const ranked = [...results]
    .map((r) => ({
      ...r,
      total: r.scores.math + r.scores.english + r.scores.science,
    }))
    .sort((a, b) => b.total - a.total);

  return (
    <ol>
      {ranked.map((r, index) => (
        <li
          key={r.id}
          className={index === 0 ? "first-place" : ""}
        >
          {index + 1}位 {r.name}(合計: {r.total}点)
        </li>
      ))}
    </ol>
  );
};

【解説】

  • [...results] でシャローコピーを作り、元の配列を変更しないようにする(sort() は破壊的メソッド)
  • map() でデータを加工してから sort() する、という処理順がポイント
  • map() の第2引数 index を使うと、ループ中の位置(0始まり)が取得できる

解説12:複合的なJSXを組み立てよう

【解答例】

const Feed = () => {
  const sorted = [
    ...posts.filter((p) => p.pinned),
    ...posts.filter((p) => !p.pinned),
  ];

  return (
    <div className="feed">
      {sorted.map((post) => (
        <div
          key={post.id}
          className={`post-card${post.likes >= 20 ? " popular" : ""}`}
        >
          {post.pinned && <span className="badge">📌 ピン留め</span>}
          <div className="post-header">
            <span>{post.user.avatar}</span>
            <strong>{post.user.name}</strong>
          </div>
          <p>{post.content}</p>
          <div className="post-footer">
            <span>❤️ {post.likes}</span>
            <span>
              {post.comments.length > 0
                ? `コメント${post.comments.length}件`
                : "コメントなし"}
            </span>
          </div>
        </div>
      ))}
    </div>
  );
};

【解説】

  • ピン留め投稿を先頭に並べ替えるには、filter() で分けたあとスプレッド構文で結合する方法がシンプル
  • テンプレートリテラルを使った className の動的結合(`post-card${...}`)はよく使われるパターン
  • コメント数の条件分岐はテンプレートリテラル内の三項演算子で簡潔に書ける