既存のRailsにReact.jsを導入する

React.jsは、ネイティブアプリのようにインタラクティブなUIを作りやすくするためのJavascriptライブラリです。

従来、Webサービス分野ではjQueryが近い機能を果たしてきましたが、React.jsはJSXの導入によりDOM操作に引きずられることなく、より凝集性の高いコードを書けるよう設計されています。

Railsプロジェクトとの組み合わせ方

RailsプロジェクトとReact.jsベースのクライアントコードは大ざっぱに分けて、以下のような3つのパターンが考えられ、それぞれメリット・デメリットがあります。

  1. react-railsを利用してAsset Pipelineに組み込む
    • Railsのビルド手順に組み込まれるため、新たに準備すべきものは少ない。一方、Javascript側のツールチェインをうまく使えず柔軟性が低い
  2. SPAのようにJavascript主体でアプリを作り切り、RailsをAPIサーバにする
    • クライアントとサーバサイドのコードを完全に分離するため、保守性の高いアーキテクチャにしやすい期待はある。ただし初物のツールの割合が多くなり目先は不透明
  3. RailsのViewの部品としてReactjsコンポーネントを埋め込む
    • アプリの基本設計はRailsそのものを流用できる。各ページ内の処理がRubyとJavascriptに分かれるため、保守性は下がる

今回は、既存プロジェクトのコードベースを生かすことを重視して、3番目のアプローチを採りました。

相対的にReact.jsの実績が乏しくJavascriptスタック主体で完成度を上げることが難しい現状では2番目のアプローチはとりづらく、逆に1番目のreact-railsではツールの選択肢が狭すぎるため、React.jsから見たオーソドックスな手法から外れてしまう懸念がありました。

既存のViewにReact.jsのコンポーネントを組み込む

React.jsのUIコンポーネントを標準的な手順で開発したら、RailsのViewに組み込む手順は比較的シンプルです。

要点だけに簡略化すると、コンパイル済のjsコードをインクルードして、コンポーネントを表示するためのユニークな空タグを出力するだけです。

<script src="/assets/javascript/bookmark_component.js"></script>

<div id="bookmark_button"></div>

このViewに対応する、bookmark_component.jsxのインターフェースは以下のようになります。ReactDOM.render()の中でgetElementById()を用いて表示するDOMを指定するだけです。

var Bookmark = React.createClass({ // コンポーネント定義 });

ReactDOM.render( (<Bookmark />),
                document.getElementById('bookmark_button')
               );

React.jsで本格的に開発していこうと考えると、おそらくJavascript側のツール整備やコードが大きくなっていくので、Railsとの接点はなるべくシンプルにしておくべきという印象です。

DOM経由でRailsの値をReact.jsに渡す

この方式で実装する場合、サーバサイドの変数をJavascriptに渡すことが難点になりがちです。

サーバーからの値の取得は、原則としてRails側でAPIを用意してAjaxで取得すべきなのですが、実験的にReact.jsを導入したい段階でAPIを開発するのが難しいというケースがあります。

その場合、DOMにERBで変数を出力しておき、Javascriptから読んでStateにセットする、という手法が使えました。(もっとも、React.jsは脱DOMを指向しているのでこれはアンチパターンの可能性もあります)

具体的な手順として、Rails側ではViewに<span id="object_id" reactdata="<%= @some_object_id %>"></span>のようなタグを出力しておきます。

React.js側ではReactコンポーネントのgetInitialStateでDOMから値を読み出してStateにsetすることで、一般的なReactの変数として使えるようになります。

var Bookmark = React.createClass({
       getInitialState: function() {
                                 return {
                                         objectid: document.getElementById("object_id").getAttribute("reactdata")
                                 };
								 },
 // コンポーネント定義 });

まとめ

React.jsをRailsプロジェクトに導入する手順の要点を紹介しました。

じっさいにはJavascriptのツールチェインを用意してワークフローを準備することもそれなりに手間がかかります。

ツール不足という側面よりも、クライアントサイドとサーバサイド間のコード構造が違うことの方がより時間のかかる課題という印象です。

けっきょくのところ、React.jsを導入したい目的には「jQueryの水準を大きく超えるインタラクティブなUIを実装したい」という意図があるはずで、これは本質的にView層のコードをかなりたくさん書こうとしていることになります。

複雑性が増すのはある意味当然なので、React.jsとRails間のインターフェースが疎結合になるように設計することが重要になります。

中馬崇尋
Chuma Takahiro