JSXにいたる歴史と考察(1/2)の続きです。前回はReact以前に使われてきたHTMLを組み立てるテンプレートエンジンの歴史と考察でした。
今回はJSXに付いて考えてみたいと思います。
JSXとは
まずは、Reactのコードの主要部を書いておきます、解説はあとでしますね。
⑤ JSX(React)のコード
const App = () => {
const items = [
{name: "チョコレート", price: 300},
{name: "おはぎ", price: 200}
];
return (
<table>
<thead>
<tr><th>商品</th><th>価格</th></tr>
</thead>
<tbody>
{items.map((item, ix) =>
<tr key={ix}><td>{item.name}</td><td>{item.price}</td></tr>
)}
</tbody>
</table>
);
}
export default App;
前回の埋め込み型テンプレートのコード(EJS)の似てるような気がしますね。
HTMLの中にコード(items.map(...
, item.name
など)が入っているように見えます。しかしこのコードはAppというJavaScriptの関数のコードです。return文の戻り値を戻す式の部分に<table>...
のようにHTMLが書かれています。不思議ですよね!
ChromeのデベロッパーツールのConsoleで以下のようにhtmlを戻すコードを書いて実行すると下画像のようにエラーになります。
いままでJSXの語源を説明してきませんでしたが、英語WikipediaのJSXには「JavaScript Syntax Extension の略で、 JavaScript XMLと呼ばれることもあります」(DeepL翻訳)と書かれています。さらに日本語化すると「JavaScript言語の文法拡張(機能) の略で、 JavaScript言語(用)XML と呼ばれることもあります」ですね。
実はReactの中で使われているJavaScriptは拡張されたもので、HTML(XML)を数値や文字列と同様のリテラルとして扱えます。HTMLを変数の代入したり、関数に渡したり、関数の戻り値として戻したりできます。⑤のコードのApp関数はHTMLを戻り値とする関数ですね。
すこし付け加えると、JSXのHTMLリテラル内には{式}
でJavaScriptの値をHTMLに埋め込めます、例えば {item.name}
。ここは埋め込み型テンプレートに似ていますね
さらに細かい事としては(読み飛ばしてもよいです)
- さらに
{式}
の式にはHTMLも書けます、例えば{<b>重要</b>}
。HTMLはReact内のJavaScriptではJavaScriptのリテラルだからです - JSXには1つのHTMLしか書けません
let a = <br/><br/>;
はエラーになります、この場合はフラグメントを使い1つのHTMLにしlet a = <><br/><br/></>;
と書きます- 補足:タグ内に子要素が複数あるのはOKです、
<br/><br/>
はフラグメント<>〜</>
の子要素なので1つのHTMLになります
- 補足:タグ内に子要素が複数あるのはOKです、
- または、配列を使い
let a = [<br/>, <br>];
と書いても良いです(後のReactコード説明で出てきます) - フラグメントがリリースされる前は
let a = <div><br/><br/></div>;
のように無意味なdivタグで括っていました
JSXの書き方
従来のテンプレートには、
- 条件判断で作成されるHTMLを切り替える
- 配列等に入ったデータを使い、テーブルやリストのようなHTMLの繰り返し構造を作成
のような機能が必要になります、埋め込み型テンプレートでは<% 〜 %>
タグ内にホスト言語のif
やfor
を書いて使います。
またHTML+α型テンプレートではv-for
やv-if
のような独自のHTML属性を付ける事でフレームワーク(ライブラリー)が、それを解釈し条件判断や繰り返しを行います。
JSXのそぼくな書き方
さて、JSXでもJavaScriptのif文やfor文を使い以下のようにも書けますが・・・
条件判断
if (a > 0) {
return <b>{a}</b>;
} else {
return <u>{-a}</u>;
}
繰り返し
let tableBodies:JSX.Element[] = [];
for (const item of items) {
tableBodies.push(<tr><td>{item.name}</td><td>{item.price}</td></tr>);
}
return (
<table>
{tableBodies}
</table>
);
// このコードを実行すると「リスト項目には key を与えるべきだ」という警告が発生します(後で説明します)
JSXの良い書き方
JSXではHTMLはリテラルですから、式の要素です。したがって式で書くとよりスマートに書けます。上の例は、
条件判断
return (a > 0) ? <b>{a}</b> : <u>{-a}</u>;
条件演算子(三項演算子とも呼ばれます)、 条件 ? 条件が成り立つ時の値 : 条件が成り立たない時の値
を使う事でスマートに書けます。
条件演算子 に不慣れな方は、このさい覚えましょう! 今時のプログラマーには必須の知識です。
繰り返し
return (
<table>
{items.map((item) =>
<tr><td>{item.name}</td><td>{item.price}</td></tr>
)}
</table>
);
// このコードを実行すると「リスト項目には key を与えるべきだ」という警告が発生します(後で説明します)
さらに細かい事としてはで説明したよう(読み飛ばした人は読んでください ^^)にHTMLの繰り返しはHTMLの配列を作れば良いので、繰り返しの基になるデータを使い対応するHTMLの配列を作れば良いので、map関数を使うと上のように繰り返しが簡単に書けます。
map関数に不慣れな方は、このさい覚えましょう! 今時のプログラマーには必須の知識です。
もうすこし解説すると items.map((item) => <tr><td>{item.name}</td><td>{item.price}</td></tr>)
を実行すると、
戻り値は [<tr><td>チョコレート</td><td>300</td></tr>, <tr><td>おはぎ</td><td>200</td></tr>]
になります。したがって下のようなJSXが作られ
<table>
{[
<tr><td>チョコレート</td><td>300</td></tr>,
<tr><td>おはぎ</td><td>200</td></tr>
]}
</table>
最終的には以下のようなHTMLが生成されます。
<table>
<tr><td>チョコレート</td><td>300</td></tr>
<tr><td>おはぎ</td><td>200</td></tr>
</table>
⑤ JSX(React)のコード解説はだいたい終わったと思いますが、繰り返しの説明コードと少し違いがありました。また解説コードにさりげなく”このコードを実行すると「リスト項目には key を与えるべきだ」という警告が発生します”と書いてありました。
⑤のコードではtr
タグにkey属性が指定されています。その値ix
はmapに渡した無名関数の第二引数で、現在処理中の要素の配列内における添字で、最初のデータに対しては0
、2つめのデータに対しては1
になります。
{items.map((item, ix) =>
<tr key={ix}><td>{item.name}</td><td>{item.price}</td></tr>
)}
key属性はReact処理系用の特殊な属性で生成されたHTMLには入っていません。今回のサンプルでは配列の内容を表示しているだけですが、順番が変更されたり、削除、追加されるアプリの場合は、どの要素がどう変わったかを確実にReact処理系が知る目的でkeyを使っています。詳しくはリストと keyを読んでください。
まとめ
React(JSX)は
- React内のJavaScriptは拡張されていてHTMLはリテラルです、数値や文字列と同じように変数に代入したり関数の引数、戻り値として使えます
- HTMLリテラル内の
{式}
と書くことで式の値をHTMLに埋め込む事ができます - 他のテンプレートとは違い、条件判断や繰り返しはコード、主に式で行います
従来のテンプレートは、HTMLにコード値の埋め込みや、条件判断、繰り返しを追加するものでした、主役はHTMLでした。
しかしJSXでは、HTMLをJavaScript言語のリテラルに取り込むことにより、コード中心の世界にHTMLが溶け込んでいるイメージでしょうか。
JSXを使いこなすには、よりJavaScript(プログラム)の世界に入ってこないといけません。このへんがWebデザイナーには好かれない原因でしょうか?
ただし、この特性があるのでいち早くTypeScript対応も出来ました。また以前はクラスベースだったReactコンポーネントも現在では手軽な関数として書けるようになりました。
今回書けなかった事
- JSXはどのように実装されているのか
- JSX(React)の歴史
- JSXの書き方の定番
- ・・・
いずれ書くと思います。