前回書いたこの1行を、もう一度見てください。
return <h1 className="p-8 text-3xl font-bold text-sky-600">しまちゃんのことりずかん</h1>JavaScriptの中に、HTMLのタグが引用符もなしで書かれています。これがJSXです。
JSXはHTMLによく似ていますが、正体はJavaScriptです。似ているぶん、違うところでつまずきます。この回でその違いを全部そろえます。
そもそも何に変換されているのか
ブラウザはJSXを読めません。ビルドのときに、こう変換されています。
// 書いたもの
<h1 className="title">しまちゃん</h1>
// 変換されたもの(イメージ)
jsx('h1', { className: 'title', children: 'しまちゃん' })タグは関数の呼び出しに、属性はオブジェクトになります。「classNameって何だ」と思ったら、この形を思い出してください。オブジェクトのキー名なのです。だからJavaScriptの都合が優先されます。
違い①:classはclassName
classはJavaScriptの予約語(クラスを作るための言葉)なので使えません。
<div className="card">…</div>同じ理由で、<label for="…">はhtmlForになります。この2つ以外はHTMLとほぼ同じです。
| HTML | JSX |
|---|---|
class | className |
for | htmlFor |
onclick | onClick |
tabindex | tabIndex |
イベントと複数語の属性はキャメルケース(2語目の頭を大文字)になる、と覚えておけば大体当たります。
違い②:値は波かっこで差しこむ
JSXの中でJavaScriptの値を書きたいときは{}で囲みます。
const name = 'シマエナガ'
return <h1>{name}のずかん</h1>属性にも使えます。引用符は付けません。
<img src={imageUrl} alt={name} />
<img src="/shima.png" alt="しまちゃん" /> {/* 決め打ちの文字列は引用符でOK */}波かっこの中に書けるのは式(値になるもの)だけです。計算・関数の呼び出し・三項演算子は書けますが、if文やfor文は書けません。
<p>{birds.length}羽います</p>
<p>{name.toUpperCase()}</p>
<p>{isRare ? 'レア' : 'ふつう'}</p>違い③:返せるタグは1つだけ
これはエラーになります。
return (
<h1>しまちゃんのことりずかん</h1>
<p>全8羽をあつめよう</p>
)関数が返せる値は1つだからです。親で包めば解決します。
return (
<div>
<h1>しまちゃんのことりずかん</h1>
<p>全8羽をあつめよう</p>
</div>
)とはいえ、包むためだけの<div>が増えるのは気持ちのいいものではありません。そこで名前のないタグが使えます。
return (
<>
<h1>しまちゃんのことりずかん</h1>
<p>全8羽をあつめよう</p>
</>
)<></>はフラグメントと呼ばれ、HTMLには何も出力されません。「まとめるためだけの入れ物」です。
違い④:閉じタグは省略できない
HTMLでは<img src="…">や<br>で閉じなくても動きましたが、JSXでは必ず閉じます。
<img src="/shima.png" alt="しまちゃん" />
<br />
<input type="text" />末尾の/を忘れると「Unterminated JSX contents」のようなエラーになります。JSXのエラーは大半がタグの閉じ忘れなので、赤い文字が出たらまずタグを数えてください。
違い⑤:コメントは{/* */}
JSXの中では、HTMLの<!-- -->は使えません。
<div>
{/* ここはコメント */}
<h1>しまちゃん</h1>
</div>波かっこでJavaScriptに戻ってから、JavaScriptのコメントを書く——という形です。タグの外(関数の中)ならふつうに//が使えます。
組み合わせるとこうなる
ここまでの決まりを全部使うと、鳥のカード1枚はこう書けます。
function App() {
const title = 'しまちゃんのことりずかん'
return (
<div className="min-h-screen bg-sky-50 p-8">
<h1 className="text-2xl font-bold text-sky-800">{title}</h1>
<p className="mt-1 text-sm text-slate-500">全8羽をあつめよう</p>
<div className="mt-6 flex max-w-md gap-4 rounded-2xl bg-white p-5 shadow-sm">
<span className="text-4xl">🐦</span>
<div>
<h2 className="font-bold text-slate-800">シマエナガ</h2>
<p className="mt-1 text-sm text-slate-600">
雪のようにまっ白な小鳥。北海道にすんでいる。
</p>
</div>
</div>
</div>
)
}
export default App見出しは{title}で変数から、カードの中身はまだ直接書いています。Tailwindのクラスは、カードの角丸(rounded-2xl)・白背景(bg-white)・影(shadow-sm)・内側の余白(p-5)という、いつもの組み合わせです。HTMLに書くのと同じクラスがそのまま使えます。
公式ドキュメントも見てみる
JSXの決まりごとは、公式にもまとまったページがあります。「JSXのルール」の節に3つのルールが並んでいるので、迷ったときの答え合わせに使えます。
ja.react.dev外部サイトJSX でマークアップを記述する – React公式の「JSXでマークアップを記述する」。ここで扱った「1つのタグで包む」「閉じタグは必須」「キャメルケース」が、公式の言葉で3つのルールとして整理されていますこのレッスンのまとめ
- JSXの正体はJavaScript。タグは関数の呼び出しに、属性はオブジェクトに変換される
class→className、for→htmlFor。イベントはonClickのようにキャメルケース- 値は波かっこ
{}で差しこむ。中に書けるのは式だけ(if文は書けない) - 返せるタグは1つだけ。余計な
<div>を増やしたくないときは<></>で包む - 閉じタグは省略できない(
<img />・<br />) - コメントは
{/* */}
次は、いま1枚だけ書いたカードを部品(コンポーネント)として切り出します。同じものを3枚並べるところまでやると、Reactの組み立て方が見えてきます。
