読者です 読者をやめる 読者になる 読者になる

Arantium Maestum

プログラミング、囲碁、読書の話題

Clojure Web Development勉強 - Reactあれこれ

React Clojurescript Clojure Web

Facebookが提供するJavaScriptライブラリであるReactについていろいろと書こうと思う。

まず、私自身がReactについて調べていた時に大変参考になった記事を三つ挙げる:

qiita.com

mizchi.hatenablog.com

qiita.com

本記事と前後してこれらも読めば、Reactについてはよく理解いただけるのではないか。

React前夜

今までのWebフロントエンドのモデルは

  1. HTMLで文書の構造を記述し
  2. CSSで見た目を整え
  3. JavaScriptでブラウザサイドの動的なロジックを加える

というもので、JQueryの出現などによって多少の動的挙動ならそれなりに記述しやすくなった。しかしブラウザ上でサービスを提供するビジネスの隆盛に伴い、デスクトップアプリケーションと同等の複雑な挙動をページリロードなしで実装するSingle Page Application(略してSPAーー昔はRich Internet Applicationとか言いましたね)が必要となってくる。

JQuery(あるいは生のJavaScriptで書くというさらなる地獄)ではこういった動的かつ柔軟なインターフェイスを実装するための基本的なモデルは「HTMLで記述された文書構造から立ち上がってくるDocument Object Modelの関連部分をJavaScriptによって逐次変更していく」というものだ。

その結果「グローバルなステートにローカルな変更を逐次与えていく」という命令型オブジェクト指向プログラミングで一番辛い流れになってしまう。

Reactモデル

Reactはその辛さを解消するための仕組みである。

HTML/CSS/JavaScriptの役割分担としては:

  1. HTMLには最低限のCSS+JavaScriptインポート、そしてReactが操作するためのフックとなる単一の空DOM要素を記述
  2. CSSは今までどおり見た目部分を記述
  3. JavaScriptで、引数によって必ず同一のDOM要素(あるいは要素のツリー)を返すコンポーネント関数を数多く記述
  4. 作ったコンポーネント関数を組み合わせてさらに大きなコンポーネント関数を作っていき、最終的にアプリケーション全体を表示するコンポーネントを作成
  5. ページの変遷はコンポーネントに与えられる引数が変わることで起きる

と、JavaScriptがHTMLを食ったような形である。実際JSXというJavaScriptの拡張言語で、より自然にHTMLタグをJSコードに埋め込んだ形式で記述することも可能になる。

HTMLで記述して描画したDOMをJavaScriptでいじるのではなく、すべてを「引数は『状態』、返り値は『DOM要素』」なJavaScriptの純粋関数で書いてしまって、状態変遷の度に単に新しい引数を渡して新しいDOMを作成してしまおう、というモデルである。

メリットとしては

  1. 引数によって描画されるものの同一性が担保されるので、アプリケーションのロジックについて考えやすくなる
  2. 同じ理由でテストが容易
  3. コンポーネント化によって再利用性が非常に高くなる

React自体からはちょっと離れるが、「Reactを使ったアプリケーションの作り方」であるFluxにおいてはさらに「Global Stateを一つのデータオブジェクトにすることで、ほとんどのロジックをそのデータに対する純粋関数として記述できる」という大きなメリットが生まれる。

しかし、このままでは状態変遷ごとに新しいDOMが作成されて描画されて、非常に効率が悪くなってしまう。DOMのローカルな部分をJavaScriptでいじるのは少なくとも「最低限のDOM変更で済む」というメリットがあったわけだ。

そこでReactの影の主役であるVirtual DOMという仕組みが生きてくる。このライブラリ側の仕組みが、「まるで新しいDOMを作成するかのように書かれたコード」をベースに「現在のDOMとあるべきDOMの差分」を算出し、その差分だけの「最低限のローカルなDOM変更のみ」を適用してくれる。宣言的に書いたコードが命令的にうまい具合に変換されるのである。

関数型言語コンパイラインタプリタが「泥臭い命令型の指示」を吸収して、プログラマにはそれらを意識することなく「純粋関数で書かれたコード」を書かせてくれるのとちょっと似てるかもしれない。

ReactとClojureScript

さて、ここまで書いたことを踏まえて考えていただくとわかると思うのだけれど、ReactとClojureScriptの相性は非常にいい。

いやむしろ

JQueryや生のJavaScriptのスタイルをそのまま使ってしまうと『DOMいじり』という非常に命令的でステートフルなモデルからしてClojureScriptの強さがまったく生きない

といった方が正解かもしれない。React的な方向にしろ別の方向(例えばHoplon)にしろ、どうにかしてその一般的なJavaScriptモデルから脱却せざるをえない。

逆にReactのような

DOMの初期構造も純粋関数の組み合わせで記述

状態変遷も本質的にはデータ構造として捉えられてるアプリケーション状態に純粋関数を適用して変換していくことで実施

というモデルではClojureScriptの効率のいいPersistent Immutable Data Structureと豊富かつ強力なデータ操作関数群が猛威を振るう。

現在比較的有名なClojureScript上のReact系ライブラリとしては

がある。

実際に私が使ったことがあるのはReagentのみ。他の二つに関して、今持っている知識と印象を書くと:

  • Om/Om-NextはClojureScriptのメインディベロッパーであるDavid Nolenのライブラリで、非常に精緻かつ先進的な機能を多く取り入れた強力なライブラリのようである。(Om-Nextは後方互換性のまったくない後継プロジェクト)ただしその分かなり独特で、Omの思想と技術的背景をある程度理解しないと使うのは難しい印象を受ける。
  • Quiescentは逆にReactをClojureScriptから使うための最小限のラッパーに近い。ただし、コンポーネントレベルで独自のステートを持つような機能がないので、Flux的な「トップレベルで一つの状態オブジェクトを持ち、そのデータが子コンポーネントに枝分かれして渡されていく」というモデルがデフォルトのようだ。

いつかこれらライブラリも是非使ってみたいものである。

Reagentの詳細は次回以降。