EY-Office ブログ

JSXにいたる歴史と考察(2/2)

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になります
  • または、配列を使いlet a = [<br/>, <br>];と書いても良いです(後のReactコード説明で出てきます)
  • フラグメントがリリースされる前はlet a = <div><br/><br/></div>;のように無意味なdivタグで括っていました

JSXの書き方

従来のテンプレートには、

  1. 条件判断で作成されるHTMLを切り替える
  2. 配列等に入ったデータを使い、テーブルやリストのようなHTMLの繰り返し構造を作成

のような機能が必要になります、埋め込み型テンプレートでは<% 〜 %>タグ内にホスト言語のifforを書いて使います。
またHTML+α型テンプレートではv-forv-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の書き方の定番
  • ・・・

いずれ書くと思います。

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ