コーダーに知っておいてもらいたい React JSX の基礎 その2

フロントエンド

Photo by Ash Edmonds

皆様どうも、こんにちは!
引き続きこまりのフロントエンドエンジニア、桑木です。

前回、ReactのJSXではJavaScript中にいきなりHTML風の記述ができて、その中にJavaScriptの式を{ }で囲むことで埋め込める。ということを説明しました。制御文を使わずにJavaScriptの式だけで繰り返しや選択を実現できる、というようなことを書いて終わりましたが、その説明は次回に持ち越して、今回はHTMLっぽい部分の説明をしたいと思います。

HTML ではなくて JSX と呼ぶしかない

ところで、今まで「HTMLっぽい部分」とか「HTML風」などと散々な呼び方をしてきましたが、その実態はReactの固有オブジェクトであってHTMLでもJavaScriptのDOMでもありません。コードの見た目はとても良く似ていますが、わかりやすいように似せているだけの別物である、という認識は持っておいた方が良いでしょう。ちなみにReactのドキュメントでは、HTML風の部分を指してJSXと言っているようです。そのJSXを含むJavaScriptのファイルもまたJSXと呼ぶのでややこしいですね。

さて、似せているとは言うものの、どこが一緒でどこが違うのでしょうか。

どちらかと言えば懐かしの XHTML

br要素やinput要素などのHTMLでは終了タグの存在しない要素も終了タグを明示しなければなりません。子要素が空ならXML風の省略記法も可能です。

<input type="text" name="username"> // エラー
<input type="text" name="username"></input> // OK
<input type="text" name="username" /> // OK

HTMLのように仕様で定められた補完もありません。例えばHTMLでは次のコードのように、table要素直下のtr要素は明示されていなければtbody要素が補完されますし、p要素中にp要素の開始タグが登場した場合には前回のp要素の終了タグが省略されたものとみなして前回のp要素は閉じられます。

// このように記述すると
<table><tr>...</tr></table>
<p>abc<p>123
// HTMLではこのように解釈されることが仕様で決まっているが
<table><tbody><tr>...</tr></tbody></table>
<p>abc</p><p>123</p>
// Reactではエラーになる

JSXにこのような補完はないので、ドキュメント構造は可能な限り正確に記述することが求められます。

終了タグがない等の構文ミスの場合は、そもそもトランスパイラが変換できないのでエラーになります。しかし、開始タグと終了タグの関係さえ合っていれば、トランスパイラが機械的にJavaScriptに変換することは可能です。

<p>a<p>b</p>a</p>

このようなJavaScriptとして問題がなくても、HTMLでは許されていないドキュメント構造がどのように描画されるかは、Reactとブラウザの実装に依存します。Reactのオブジェクトとして問題がある場合、Reactがブラウザのコンソールにエラーメッセージ(と解決のヒント)を出力するので、コンソールはチェックするようにしてください。

属性名は概ね JavaScript の DOM

さて、要素名はHTMLと同じと考えて問題ないのですが、その要素の属性値はHTMLというよりもDOMのHTMLElementなどのプロパティ名に近いものです。といっても意味がわからないと思うので先に実例を見てみましょう。

<input type="text" class="username-input" readonly> // HTML
<input type="text" className="username-input" readOnly={ true } /> // JSX

class属性はclassNameという名前になっています。readonly属性はreadOnlyと途中が大文字になっていますし、値もreadonly="readonly"という正式なHTMLの値ではなく{ true }とJavaScriptの式を指定しています。

まず属性名ですが、これはReact独自というわけではなく元々JavaScriptでDOMを扱う際に使用していたプロパティ名です。

var username = document.createElement("input");
username.type = "text";
username.className = "username-input";
username.readOnly = true;

そのプロパティの型が文字列の場合は、JSXでもHTMLと同じようにname="hogehoge"と書くことが可能です。数値(colSpan等)や真偽値の場合には{ }を使用してJavaScriptの値として指定する必要があります。

このように、属性名や型については限りなくDOMに似ているものの、前述の通り似せているだけなので全く同じわけではありません。Reactが対応している属性については公式ドキュメントを参照してください。これを見れば属性名の参考にもなると思います。なお、HTMLそのままの属性名を書いたら、これもまたReactが律儀にエラーメッセージで修正のヒントを教えてくれます。

次回へ続きます。