JSX を理解しよう
JavaScriptの中にHTMLを書ける構文「JSX」の仕組みと書き方を学びます。
このチャプターで学ぶこと
- JSXがJavaScriptの糖衣構文であることを理解できる
- HTMLとJSXの違い(className、htmlFor など)を説明できる
- 波括弧 {} を使って動的な値を埋め込める
- フラグメント <></> を使って複数要素を返せる
- 自己紹介カードをJSXで作れる
JSX を理解しよう
前のチャプターでは App.jsx の中にHTMLのようなコードが書かれているのを見ました。あれは JSX という構文です。このチャプターでJSXをしっかり理解しておきましょう。
JSXとは何か
JSXは「JavaScript XML」の略で、JavaScriptの中にHTMLライクな構文を書けるようにした拡張機能です。
// これがJSX
const element = <h1>こんにちは</h1>;
見た目はHTMLですが、実際にはJavaScriptです。Viteなどのビルドツールが、このJSXを通常のJavaScript関数呼び出しに変換します。
// ビルド後のJavaScript(実際には人間が書かなくてよい)
const element = React.createElement('h1', null, 'こんにちは');
React.createElement を毎回手書きするのは大変なので、JSXという便利な構文が生まれました。Laravelのbladeテンプレートが最終的にHTMLに変換されるのと似た仕組みです。
JSXを使うために特別なインポートは不要です(React 17以降)。Viteのテンプレートは最初からJSXが使えるように設定されています。
HTMLとJSXの違い
JSXはHTMLとよく似ていますが、いくつか重要な違いがあります。ここをしっかり覚えておかないとエラーの原因になります。
1. class ではなく className
HTMLでは要素にクラスを付けるとき class を使います。しかしJavaScriptでは class は予約語(classの定義に使う)なので、JSXでは className を使います。
// HTML
<div class="container">...</div>
// JSX(正しい書き方)
<div className="container">...</div>
2. for ではなく htmlFor
<label> の for 属性も同様に、for がJavaScriptの予約語(forループ)なので htmlFor に変わります。
// HTML
<label for="email">メールアドレス</label>
<input id="email" type="email" />
// JSX(正しい書き方)
<label htmlFor="email">メールアドレス</label>
<input id="email" type="email" />
3. 自己閉じタグが必須
HTMLでは <input> や <img> は閉じタグなしで書けますが、JSXでは必ずスラッシュで閉じる必要があります。
// HTML(これはOK)
<input type="text">
<img src="photo.jpg" alt="写真">
<br>
// JSX(必ずスラッシュで閉じる)
<input type="text" />
<img src="photo.jpg" alt="写真" />
<br />
4. スタイルはオブジェクトで書く
インラインスタイルを書く場合、JSXではCSSの文字列ではなくJavaScriptオブジェクトを使います。プロパティ名はキャメルケースになります。
// HTML
<p style="color: red; font-size: 16px;">テキスト</p>
// JSX
<p style={{ color: 'red', fontSize: '16px' }}>テキスト</p>
外側の {} はJSXに式を埋め込む記号、内側の {} はJavaScriptオブジェクトのリテラルです。
font-size のようにハイフン区切りのCSSプロパティは、JSXでは fontSize のようなキャメルケースに変換します。background-color → backgroundColor、border-radius → borderRadius といった具合です。
式を埋め込む {}
JSXの中で波括弧 {} を使うと、JavaScriptの式を埋め込めます。これがJSXの最も便利な機能です。
function Greeting() {
const name = '山田太郎'
const currentYear = new Date().getFullYear()
return (
<div>
{/* 変数を表示 */}
<h1>こんにちは、{name}さん!</h1>
{/* 計算結果を表示 */}
<p>今年は{currentYear}年です</p>
{/* 三項演算子で条件分岐 */}
<p>{name.length > 3 ? '長い名前ですね' : '短い名前ですね'}</p>
</div>
)
}
{} の中には 式 を書きます。if文 や for文 などの 文 は直接書けません。条件分岐には三項演算子 ? : や && 演算子を使います。
function StatusBadge() {
const isLoggedIn = true
return (
<div>
{/* && 演算子:左辺がtrueのときだけ右辺をレンダリング */}
{isLoggedIn && <span>ログイン中</span>}
{/* 三項演算子:条件によって表示を切り替え */}
<p>{isLoggedIn ? 'ようこそ!' : 'ログインしてください'}</p>
</div>
)
}
JSXのコメントは {/* コメント */} と書きます。HTMLの <!-- --> やJavaScriptの // はJSXの中では使えません(属性値の外のJavaScript部分では // が使えます)。
配列のレンダリング
map() を使うと配列をJSXのリストに変換できます。これはよく使うパターンです。
function FruitList() {
const fruits = ['りんご', 'バナナ', 'みかん']
return (
<ul>
{fruits.map((fruit) => (
// key はReactが差分を効率よく計算するために必要
<li key={fruit}>{fruit}</li>
))}
</ul>
)
}
map() でリストをレンダリングするときは、各要素に必ず key 属性を付けてください。key はリスト内で一意な文字列または数値である必要があります。key を省略するとコンソールに警告が表示されます。
フラグメント <>...</>
Reactのコンポーネントは 必ず1つのルート要素 を返す必要があります。複数の要素を返したいとき、余分な <div> で囲むとHTMLの構造が汚れてしまいます。そこで使うのが フラグメント です。
// NG: 複数の要素をそのまま返せない
function Bad() {
return (
<h1>タイトル</h1>
<p>本文</p> // SyntaxError!
)
}
// OKだがHTMLに余分なdivが増える
function WithDiv() {
return (
<div>
<h1>タイトル</h1>
<p>本文</p>
</div>
)
}
// ベスト:フラグメントを使う
function WithFragment() {
return (
<>
<h1>タイトル</h1>
<p>本文</p>
</>
)
}
フラグメント <> は実際のDOMには何も追加しません。HTMLを余計な要素で汚さずに複数の要素をグループ化できます。
<> は <React.Fragment> の短縮記法です。key 属性を付けたい場合(リスト内など)は <React.Fragment key={id}> と書く必要があります。
属性に動的な値を渡す
属性値にも {} を使って動的な値を渡せます。
function UserAvatar() {
const userName = '山田太郎'
const avatarUrl = 'https://example.com/avatar.jpg'
const isActive = true
return (
<div>
{/* 文字列以外の値はすべて {} で渡す */}
<img
src={avatarUrl}
alt={`${userName}のアバター`}
width={64}
height={64}
/>
{/* 条件によってクラスを切り替える */}
<span className={isActive ? 'status active' : 'status inactive'}>
{isActive ? 'オンライン' : 'オフライン'}
</span>
</div>
)
}
src/App.jsx を編集して、自己紹介カードを作ってみましょう。以下の要件を満たしてください:
- 名前を変数
nameに入れて{}で表示する - 好きなもののリストを
map()で表示する classNameを使ってスタイルを当てる(CSSはApp.cssに書く)- 年齢が20歳以上なら「大人」、未満なら「未成年」と表示する
参考コード:
// src/App.jsx
function App() {
const name = 'あなたの名前'
const age = 25
const hobbies = ['プログラミング', '読書', '料理']
return (
<div className="card">
<h1 className="card-name">{name}</h1>
<p className="card-age">
年齢:{age}歳({age >= 20 ? '大人' : '未成年'})
</p>
<h2>趣味</h2>
<ul className="hobby-list">
{hobbies.map((hobby) => (
<li key={hobby}>{hobby}</li>
))}
</ul>
</div>
)
}
export default Appsrc/App.css に以下を追記してスタイルを整えてみましょう:
.card {
max-width: 400px;
margin: 2rem auto;
padding: 2rem;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card-name {
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.hobby-list {
list-style: none;
padding: 0;
}
.hobby-list li {
padding: 0.3rem 0;
border-bottom: 1px solid #eee;
} 完成したらこんな見た目になります:
まとめ
このチャプターで学んだことをおさらいしましょう:
| HTML | JSX |
|---|---|
class="" | className="" |
for="" | htmlFor="" |
<input> | <input /> |
style="color: red" | style={{ color: 'red' }} |
<!-- コメント --> | {/* コメント */} |
JSXのポイントをまとめると:
{}でJavaScriptの式を埋め込める(文は書けない)- 複数要素を返すときは
<>...</>フラグメントを使う map()でリストをレンダリングするときはkey属性を忘れずに- 属性値にも
{}で動的な値を渡せる
次のチャプターでは、このJSXをコンポーネントという単位に分割して再利用可能にする方法を学びます。