ReactやVueのJSXについて曖昧に理解する


JSXの事始め

Reactを勉強し始めに 「JSXとはなんぞや」 というのを理解するとき 「なんとなくHtml風に書けるJavaScriptの拡張構文」 と理解している人が多いと思う。

ただ 「JSXはJavaScriptに変換される」 というのをどこかで勉強しないと途中でつまづくので、JSXについての理解をもう少し深める必要がある。

JSXはJavaScriptに変換される

babelの変換結果を見れば一発なのだけど、JSXを書いているとき、babelでは次のように変換しているのだということを理解しておく必要があるんだけど、これについて解説しているものがあまりない。

例えば次のコード

import React from 'react';

function render() {
  return <div>Foo</div>;
}

これはbabelでは次のように変換される

import React from 'react';

function render() {
  return React.createElement('div', null, 'Foo');
}

つまり 我々がJSXを書いているとき、それは実際にはReact.createElementを書いている ということ。
もう少し複雑にしてみる

import React from 'react';

function render() {
  return (
    <ul>
      <li>Foo</li>
      <li>Bar</li>
    </ul>
  );
}

これは次のように変換される

import React from 'react';

function render() {
  return React.createElement( 
    'ul',
    null,
    React.createElement('li', null, 'Foo'),
    React.createElement('li', null, 'Bar')
  );
}

どう見てもReact.createElement書くより、JSXの構文で書いた方がスッキリする。
これを理解していると「JSXは存在するべくして存在するのだ」ということに納得できるんじゃないだろうか。
またJSXのとき import React from 'react'; が一見不必要そうに見えて実は必要な理由は、変換後のコードを見れば分かってもらえるのではないかと思う。

初学者のうちは「HtmlをJSの中に書いている」という感覚でも構わないんだけど、ある程度理解が進んだらHtmlは書いてないんだなと理解しないと、文字列でHtmlを組み立てるコードを書きたくなり、でもJSXだと出来ないことにモヤモヤしたりする(経験者談)
Htmlは文字列で扱うのに長けているけども、そのHtmlの特性をJSXでは発揮できない、というのが結構大きな違いだと思う。

JSXをReact以外で使う

ところでこのJSX、要するに

関数(決まった引数)

にという形に変換するだけなので React.createElement を別の関数にする、とすれば、他のライブラリでも使えそうである。
この「React.createElement を別の関数にする」を実現するのが transform-react-jsx というbabelプラグインである。

transform-react-jsxを入れて、babelの設定を次のようにする

"plugins": [
  ["transform-react-jsx", {"pragma": "h"}]
]

ここの {"pragma": "h"} というのがミソで、普通だったら React.createElement と変換される部分を、任意の文字に置き換えてくれる。

例えばVueのコード

new Vue({
  el: '#app',
  render: function(h) {
    return <div>Foo</div>;
  },
});

これは次のように変換される

new Vue({
  el: '#app',
  render: function (h) {
    return h('div', null, 'Foo');
  }
});

Vueの場合は React.createElement に相当する役割の関数 h が引数で渡ってくるので、それを使ってJSXを利用している。
renderの引数を h にしているコードをよく見ると思うけど、要するにJSXを h 関数に変換するから引数も h にしているだけなので、babelの pragma 設定を変えれば h である必要はないんだけど、仮想DOM界隈ではよく h を使うことがお決まりになっている。