《2020 年 10 月 1 日追記》
この記事の内容をさらに練った上で総括したものを**『りあクト! TypeScriptで始めるつらくないReact開発 第3版【Ⅱ. React基礎編】』**の「第5章 JSX で UI を表現する」に収録しています。
ほぼ 3 年越しのセルフアンサー本です。リンク先の無料サンプルで読めます。
プロローグ
本来「キモい」という主観の表明に正しいも間違っているもないので反論などは成り立たないとは思うのですが、世界での DL数では他のフロントエンドフレームワークを圧倒し、もはや jQuery さえ凌駕する React に対して、食わず嫌いの正当化のための言説に用いられている感すらあるので、一度ちゃんと論じておきたいテーマでした。
なお想定する対象読者は React を本格的に使ったことのないエンジニアですので、バリバリ React を使っている人には当たり前すぎることしか書きません。読んだ後に「時間の無駄だった」と言われても困りますので、あらかじめご了承ください。
話を戻して、たとえば Google 検索で「JSX k...」と入力すると、
こんなふうに「気持ち悪い」がサジェストされますし、Twitter でエゴサーチすれば「JSX キモい」「JSX 気持ち悪い」でそれぞれ数十件ヒットします。
ただそういった書き込みを端から読んでいくと、「今ではキモいと思わなくなりました」とか「あれほど気持ち悪いと思ってた JSX も今では心地よく感じる」というような意見もチラホラ見つかります。
かく言う私も React をさわり出してようやく1年くらいで、それ以前はただ斜め読みしたサンプルコードの断片を見てなんかゴチャゴチャしてて書きにくそう/読みづらそうと思っていたので、「キモい」と言いたくなる気持ちも実はわからなくもありません。
ですので「JSX キモい」とは誰が言っているのか、はたまた彼らの「キモい」という感想の裏にどんなバックグラウンドがあるのかを考察していきたいと思います。
他のフロントエンドフレームワークとの比較
「React は View ライブラリであってフレームワークではない」というのは重々承知の上で、よく比較される Vue や Angular と比較してみましょう。
- 1
- 2
- 3
- 4
というリストを生成したい場合の3つのサンプルコードは以下のようになります。
<ul v-for="n in 4">
<li>{{ n }}</li>
</ul>
<ul *ngFor="let n of _.range(1, 5)">
<li>{{ n }}</li>
</ul>
<ul>
{_.range(1, 5).map(n =>
<li>{n}</li>
)}
</ul>
(※ 下2つのサンプルは Lodash を読み込んでいる部分のコードを省略)
一見したところのコード記述量の少なさは (1) > (2) ≒ (3) といったところでしょうか。Vue テンプレートコードのシンプルさから見れば、JSX のコードは理解しづらいかもしれません。
ですが何が理解を難しくしているかというと、これら全てがテンプレート言語だという先入観です。(3)には(1)(2)のようには注釈に「〜テンプレート」とつけてません。
ありがちな誤解ですが JSX はテンプレート言語ではありません。その名前が示す※通り、JavaScript の記法拡張です。(※ JSX は「JavaScript eXtension」の略)
JSX で書かれる HTML 記法、たとえば
<h1>Hellow, world!</h1>
は、
React.createElement('h1', 'Hellow, world');
と同義です。
React は単なる View ライブラリだと章の最初に書きましたが、React を使ったアプリ開発ではロジックとテンプレートといった区別は一切なく、全てを JavaScript で記述します。その際、HTML の部分はすべて createElement()
を使って書いてもいいのですが、それだとさすがに不便なので JSX というシンタックスシュガーが用意されているというだけの話です。
(3) のコードを HTML ではなく JavaScript(ES2015) だと思って読んでみましょう。あら不思議、だんだんキモくなくなってきます。
さらに React 慣れしてくると、むしろ (1) の v-xxx
や (2) の *ngXxx
のほうがキモいと感じるようになってきます。なぜならこれらは、Vue や Angular が用意した、他では全く通用しない独自リテラルだからです。
JSX は Pure JavaScript に HTML に限りなく近い※拡張記法が付与されたものであり、JS が読み書きできる人なら新しく学ぶ必要のあることはさほど多くありません。
(※ 「限りなく近い」というのは、JavaScript の予約語を避ける(class
→className
等)必要もろもろの事情で、100% HTML そのものではないため)
サーバサイドWAF との比較
2016年5月と多少古いですが「React.js界隈の人に聞きたい」という、React に対してかなり批判的な記事が界隈でバズりました。JS を落とす一方で Python や Ruby を持ち上げているので、投稿者はサーバサイド開発にどっぷり浸かっている人であることが推察されます。中身は割りとありがちな内容なのですが、その返信記事のほうが私は納得がいくところがあったので、ここに引用したいと思います。
この辺りの一連の発言を見るに、多分React以前の前提がいろいろ違っています。単にJSやNodeやNPMやSPAやWeb APIといったフロントエンドの世界観に対して、興味がないどころか漠然とした不信があり、サーバ側でヘビーにHTMLを作って吐くスタイルを守り続けたい人なのだ、という印象を受けます。
https://anond.hatelabo.jp/20160522120724
Rails に代表される MVC アーキテクチャの考え方は、まずロジック的に必要な処理をいったん全部終わらせて、しかる後にそれを HTML に落とし込むというものです。最終出力はあくまで静的な一枚岩の HTML であるため、HTML を基本文法としそれに分岐やループのような機能を付加するための独自リテラルを追加したテンプレートエンジンがフレームワークには用意されています。
いっぽう、React を理解するための最も重要なキーワードは「Virtual DOM」でも「Flux アーキテクチャ」でもなく、「コンポーネント指向」です。React では全てのアプリケーションはコンポーネントを組み合わせることによって作られます。
コンポーネントとは、構造と見た目と振る舞いがセットになった要素であり、コンポーネントの理想は個々がアプリケーションから切り離されても独立して動く、自己完結的なものです。
React のアプリケーションでは個々のコンポーネントが並列に処理され、準備が終わったコンポーネントから順次、非同期的に描画されていきます。MVC アーキテクチャとは対照的で、サーバサイド開発が長かった人が理解するためには、それまでのどっぷり浸かっていた思想から頭を切り替える必要があります。
また React のターゲットは今や Web アプリケーションだけではありません。React Native を使えば、iOS や Android、Windows アプリまでが作れてしまいます。React が考えるのは、あくまでコンポーネントをいかに生成するかです。React にとって HTML は Web アプリケーションをターゲットにした際の「コンポーネントを作成するための DSL」でしかありません。コンポーネントを記述するための表現が HTML かどうかは、React にとっては重要な関心事ではないのです。
サーバサイド WAF の最終生成物は静的な一枚岩の HTML であり、そういったいかに綺麗な HTML が出力されるかが目的のテンプレートエンジンに慣れてしまっていると、これらを読み違います。「Webアプリケーションは計算結果を HTML として出力するものである」という強固な思い込みから来る拒否反応の最たるものが「JSX キモい」ではないでしょうか。
それゆえ彼らは React ではなく見た目がサーバサイド WAF 付属のテンプレートエンジンによく似た Vue などに流れていきがちなのでしょう。でも Vue ですら今はコンポーネント指向を採り入れているので、その理解レベルで Vue を使ってもうまく使えないのではないかと思います。
「ロジックとデザインの分離」 vs 「コンポーネント指向」
ここまでの説明を受け入れられた人でも、まだ現実の問題として業務に React(と JSX)を使うのは難しいと言われるかもしれません。その現実の問題とは「そうは言ってもデザイナーさんに JSX 書けんの? 書けないでしょ」ということです。
これまでのサーバサイドWAF が HTML テンプレートエンジンを採用していたのは、MVC アーキテクチャによる関心の分離という面もありますが、より現実的なソリューションとして「ロジックとデザインの分離」により View の部分を Web デザイナーに分業してもらえるということがあったと思います。ERB や Haml といったテンプレート言語は、エンジニアでなくてもさほど習得が難しくないので、デザイナーに勉強してもらって、View ファイルを作ってもらっていたという現場が多かったと思います。
それは平和な時代だったかもしれません。しかし近年のスマートフォンアプリの隆盛によって、ユーザーが Web アプリにも同等の UI・UX を求めるようになり、開発フローもそれに合わせるトレンドというか圧力がその時代の終わりの扉を開いてしまいました。複雑化する一方の Webアプリケーション、そしてその開発がどんどんカオスになっていた状況に React が用意した答えこそが「コンポーネント指向」です。
より複雑なシステムを人間の限界のある頭で作るためには、全体を独立したパーツに細分化してそこに複雑さを閉じ込めるのが定石です。それらのパーツを組み合わせることで複雑な機能を実現していこうというのがコンポーネント志向なのです。
そしてコンポーネントにアプリケーションからの独立性を保たせようとすれば必然的に、構造と見た目と振る舞いをセットにする必要があります。つまりコンポーネント指向ではロジックとデザインはむしろ混在するもので、分離は根源的に難しいのです。
さらにネイティブアプリ並みに複雑になったアプリでは、デザインとロジックの分離はむしろ素早いフィードバックへの足かせになってしまいます。1つのページでもインタラクティブに大きく変更して、様々な要素が入れ替わるので、デザイナーが編集できるような一枚岩の HTML では表現できないためです。じゃあどうするか。
結論から言うと、デザイナーが HTML や CSS を書く時代は終わりました。それらはすでにフロントエンドエンジニアの領分です。私が知る限り、React を採用した SPA 開発の現場ではたいていそうなっていました。デザイナーさんたちはまずプロトタイピングツールでデザインプロトタイプを作り、その後に細かなマージンや正確な色を指定した Photoshop ファイルなどを渡し、渡されたフロントエンドエンジニアがそれに従って HTML や CSS を書くというフローです。
私も従来の分担に慣れていたので最初は戸惑いましたが、ネイティブアプリ並みに高機能な SPA を開発するためにコンポーネント指向を推し進めると、自然とこのやり方に行き着くのでしょう。私のようにサーバサイド開発からフロントエンド開発に移ってきた人は苦労するでしょうが、がんばって勉強してくださいとしか言えません。最近のクラウド型デザインツール、Zeplin や Figma では HTML や CSS のエクスポート機能があるので、それらを使っていればさほど大変ではないかと思います。
また近年の Web アプリケーションの複雑化に伴い、CSS のコード量も膨大なものになって、クラス等の名前をバッティングさせないために BEM や SMACS といった手法による管理の試みがなされてきましたが、コンポーネント指向の開発に則ればそんな煩わしい悩みからも開放されます。
CSS Modules や styled-components といったライブラリを利用すれば、クラス名にランダムなハッシュをつけるなどして名前空間を自動的に閉じてくれるので便利です。
まとめ
- HTML ベースのテンプレート言語と、View を JS で記述するためのシンタックスシュガーを同列視するべきではない
- JSX には独自リテラルがほとんどなく、素直な JS そのものである
- 「Webアプリケーションは計算結果を HTML として出力するものである」という思想は、現代の複雑化していく Webアプリ開発においては時代遅れになりつつある状況を認識しよう
- 「コンポーネント指向」はその複雑性に立ち向かうための有力なアプローチであり、これを理解せずして「ロジックとデザインの分離」を絶対視するべきではない
- デザイナーさんには本来のデザインの業務に戻ってもらおう。マークアップはフロントエンドエンジニアの仕事
「JSX キモい」という意見に対して、React 歴1年足らずのエンジニアが反論してみました。JSX キモくない!
p.s.
それにつけても Qiita Markdown の Syntax Highlight は、いつになったら JSX 記法に対応するの? 当然ながら GitHub はとっくの昔に対応してる。
p.s. の p.s.
公式にリクエストしたところ、JSX・TSXに対応してくれました。ありがとうございます!