JSX でマークアップを記述する
JSX とは JavaScript の拡張であり、JavaScript ファイル内に HTML のようなマークアップを書けるようにするものです。コンポーネントを書く手段はほかにも存在しますが、ほとんどの React 開発者は JSX の簡潔さを好んでいるため、ほとんどのコードベースで JSX が使われています。
このページで学ぶこと
- React がマークアップとレンダリングロジックを混在させる理由
- JSX と HTML の違い
- JSX で情報を表示する方法
JSX: JavaScript にマークアップを入れ込む
これまで、ウェブは HTML、CSS そして JavaScript を使って作られてきました。長年にわたり、ウェブ開発者はコンテンツは HTML で書き、デザインは CSS で書き、ロジックは JavaScript で書き、そして大抵の場合はそれらを別ファイルにしていました。コンテンツが HTML 内にマークアップされる一方で、そのページのロジックは別ファイルの JavaScript に存在していました。
しかしウェブがよりインタラクティブなものになるにつれ、ロジックがコンテンツの中身をも決めるようになっていきました。JavaScript が HTML の領分も担当するようになったのです! これが、React ではロジックとマークアップを同じ場所、すなわちコンポーネントに書く理由です。
ボタンのレンダリングロジックとマークアップを同じ場所に書くことで、それらが毎回の編集時に同期されることが保証されます。逆に、ボタンのマークアップとサイドバーのマークアップといった互いに関係のない詳細は、互いに分離されるようになるため、それぞれをより安全に独立して更新できるようになります。
個々の React のコンポーネントは JavaScript の関数であり、React がブラウザに表示するためのマークアップを含めることができます。そのマークアップを表現するのに、React コンポーネントは JSX と呼ばれる拡張構文を使用します。JSX は HTML ととてもよく似ていますが、より構文が厳密であり、動的な情報を表示することができます。理解するには、HTML マークアップを JSX マークアップへと変換してみるのが最もよいでしょう。
HTML を JSX に変換する
このような(まったく正しい)HTML があるとしましょう:
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Invent new traffic lights
<li>Rehearse a movie scene
<li>Improve the spectrum technology
</ul>
これをコンポーネントの中に入れたいとします:
export default function TodoList() {
return (
// ???
)
}
そのままコピー・ペーストした場合、うまく動きません:
export default function TodoList() { return ( // This doesn't quite work! <h1>Hedy Lamarr's Todos</h1> <img src="https://i.imgur.com/yXOvdOSs.jpg" alt="Hedy Lamarr" class="photo" > <ul> <li>Invent new traffic lights <li>Rehearse a movie scene <li>Improve the spectrum technology </ul>
これは、JSX の方が厳密であり、HTML よりも若干ルールが多いからです。上記のエラーメッセージを読めばマークアップの修正方法は分かるようになっていますが、今は以下のガイドに従えば大丈夫です。
JSX のルール
1. 単一のルート要素を返す
コンポーネントから複数の要素を返すには、それを単一の親タグで囲みます。
例えば <div>
を使うことができます。
<div>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</div>
マークアップに余分な <div>
を加えたくない場合は、代わりに <>
と </>
を使うことができます。
<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</>
この中身のないタグはフラグメント (Fragment) と呼ばれるものです。フラグメントを使えば、ブラウザの HTML ツリーに痕跡を残すことなく、複数の要素をまとめることができます。
さらに深く知る
JSX は HTML のように見えますが、裏ではプレーンな JavaScript オブジェクトに変換されます。関数から 2 つのオブジェクトを返したい場合、配列でラップしないといけませんよね。2 つの JSX タグを返したい場合に別のタグかフラグメントでラップしないといけないのも、同じ理由です。
2. すべてのタグを閉じる
JSX ではすべてのタグを明示的に閉じる必要があります。<img>
のような自動で閉じるタグは <img />
のようになりますし、<li>oranges
のような囲みタグは <li>oranges</li>
と書かなければなりません。
Hedy Lamarr の画像とリスト項目は、閉じタグを書いた状態では以下のようになります。
<>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
/>
<ul>
<li>Invent new traffic lights</li>
<li>Rehearse a movie scene</li>
<li>Improve the spectrum technology</li>
</ul>
</>
3. (ほぼ)すべてキャメルケースで!
JSX は JavaScript に変換され、中に書かれた属性は JavaScript オブジェクトのキーになります。コンポーネント内では、これらの属性を変数に読み出したくなることがよくあります。しかし JavaScript の変数名には一定の制約があります。例えば、名前にハイフンを含めたり class
のような予約語を使ったりすることはできません。
このため、React では多くの HTML および SVG の属性はキャメルケースで書かれます。例えば stroke-width
の代わりに strokeWidth
を使います。class
は予約語なので、React では className
を使います(対応する DOM プロパティが由来となっています)。
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
全リストは React DOM コンポーネントに存在する属性の一覧にあります。何かを間違ったとしても心配は要りません。ブラウザのコンソールにメッセージと修正の提案が表示されるようになっています。
ヒント:JSX コンバータを使う
既存のマークアップの属性をすべて書きかえていくのは時に面倒です! 既存の HTML や SVG を JSX に変換する場合はコンバータを使うことをお勧めします。コンバータは実用上非常に役に立ちますが、自分でも楽に JSX が書けるよう、何が起こっているのかを理解しておくことも大切です。
最終結果は以下のようなものになります。
export default function TodoList() { return ( <> <h1>Hedy Lamarr's Todos</h1> <img src="https://i.imgur.com/yXOvdOSs.jpg" alt="Hedy Lamarr" className="photo" /> <ul> <li>Invent new traffic lights</li> <li>Rehearse a movie scene</li> <li>Improve the spectrum technology</li> </ul> </> ); }
まとめ
これで JSX が存在する理由と、コンポーネント内での使い方について理解しました。
- レンダリングロジックとマークアップは互いに関連しているので、React ではそれらをグループ化する。
- JSX は HTML と似ているがいくつかの違いがある。必要ならコンバータを使える。
- エラーメッセージを見れば、大概はマークアップの修正方法について指針が得られる。
チャレンジ 1/1: HTML を JSX に変換する
この HTML はコンポーネント内に貼り付けられたものですが、正しい JSX ではありません。修正してください。
export default function Bio() { return ( <div class="intro"> <h1>Welcome to my website!</h1> </div> <p class="summary"> You can find my thoughts here. <br><br> <b>And <i>pictures</b></i> of scientists! </p> ); }
手作業で直すかコンバータを使うかはお任せします!