モチベーション
Virtual DOMを用いたフロントエンド開発をしたい
Reactとは
ReactはFacebookが開発したViewを実装するためのjavascriptライブラリである。Facebook, Instagram, Github Atomなどの海外サービスで利用されており、最近発売されたWEB+DB PRESS Vol.86でも特集として取り上げられるなど日本でも注目を集めている。AngularJSやBackbone.jsのようなフレームワークと比較されることが多いが、Reactはあくまでライブラリなので、他のフレームワークやライブラリとの併用も容易である。
なぜReactを使うのか?
Reactの特徴は高速かつシンプルで保守性の高いコードを書けることに尽きると思っている。それを支えているのは以下の特徴である。
- シンプル(利用が容易)である
- Virtual DOMによるレンダリング効率の向上
- コンポーネント指向で保守性、可読性が高い
一つ一つ具体的に見てみよう。
1. Reactのシンプルさ
従来のようなjQueryを使ったViewの操作はDOMに状態を持たせることになる。例えば、以下のようなページが与えられた時にユーザがボタンをクリックする回数でDOMに追加される<h1>Hello jQuery</h1>
の数は変化する。このDOMの状態は開発者が管理することはできない。
$(function(){
$("button").click(function(){
if($("#added").length == 0) {
$("#hoge").append("<h1 id='added'>Hello jQuery</p>");
}
});
});
See the Pen jquery_sample by Takayuki Watanabe (@takanabe) on CodePen.
コードが短いうちは問題にはならないが、大規模なアプリケーションとなるとありとあらゆるDOMの状態を考慮したコーディングが必要になるため、必然的にコードは複雑になり保守性が著しく低下する。AngularJS,Backbone.js,Vue,jsなどの最近流行りのjavascriptフレームワークはDOMの管理を分割して行うデータバインディング方式を採用しており、jQueryのような複雑なDOMの管理を避ける事ができる。しかし、どのフレームワークもそれなりに重く、学習コストが高い。一方で、ReactはViewの実装に特化したライブラリなので覚える用語やルールは少なく簡単に使える、Viewのロジックとアプリケーションロジックを分離できるため将来Reactを利用しなくなってもコードの再利用性が高いなどの利点がある。
### 2. Virtual DOMによるレンダリング効率の向上
Ajax登場前後とReactによるDOMの操作はそれぞれ以下のようになる。
![20150520_dom_tree_comparison 20150520_dom_tree_comparison](https://farm6.staticflickr.com/5344/17241956003_af55fd23d8_o.png)
Ajax以前のWebアプリケーションと言えは、イベントが発生したらサーバでhtmlを生成して、レンダリングし直すことでViewの更新をしていた。この、Viewを更新するときは必ず全てをレンダリングし直す方式は開発者からするとシンプルな実装で済む上、状態管理も容易であるためありがたい。一方でサーバリソース、ネットワークリソースを無駄に消費する問題がありUXの低下を招く。AjaxによるWebアプリケーションは直接DOMの状態を変化させるため、全てをレンダリングし直す場合に要したリソースの無駄を防ぐことができるが。一方でDOMが状態を持つ点、コードの保守性、可読性が低下するなど別の問題を生んだ。ReactはAjax前後のWebアプリケーションの問題をVirtual DOM(VDOM)を導入することで解決している。VDOMはReactで導入されているDOMの抽象化概念である。Reactでは従来のようにDOMを直接操作するのではなくメモリ上にDOMと同じ構造のVDOMを作る。Viewの状態変化を検知すると状態変化前後のVDOMを比較し、その差分をパッチとしてオリジナルのDOMに当てることで効率的なレンダリングを実現する。このVDOMのおかげで開発者はViewの更新を全てレンダリングし直す時と同じ感覚でコードを書ける。DOMの構築速度の比較については[ここ](https://html5experts.jp/hokaccha/13301/)と[ここ](https://www.codementor.io/reactjs/tutorial/reactjs-vs-angular-js-performance-comparison-knockout)を参考にして頂きたい。
### 3. コンポーネント指向により保守性・可読性が高い
Reactはアプリケーションの構築をコンポーネントの組み合わせによって行う。コンポーネントによるViewの実現は以下の特徴を有しており、保守性、可読性の向上を支えている。
* 親コンポーネントが状態管理を一手に引き受けるため、子コンポーネントで状態の管理をしなくて良い
* 開発速度が爆発的に向上することはないが、コードのどの部分がViewのどの部分に対応しているかわかりやすい
* データの流れが一方向で親コンポーネントから子コンポーネントにデータの引き渡しが行われるため、データの流れが追いやすい
以下は、先ほどjQueryで実装したものをReactに変換したものである(表示する文字はHello Reactにしている)。Appコンポーネントは全ての子コンポーネントを束ねており、その子コンポーネントであるMessageコンポーネント、Buttonコンポーネントでそれぞれテキスト、ボタンに関するViewを分割実装している。
var React = require('react');
var App = React.createClass({
getInitialState: function(){
return {
message: "hello React",
buttonClicked: false
};
},
addMessage: function(){
this.setState({
buttonClicked: true
});
},
render: function(){
return(
<div>
<Message message={this.state.message} buttonClicked={this.state.buttonClicked} />
<Button onButtonClick={this.addMessage} />
</div>
);
}
});
var Message = React.createClass({
render: function(){
if(this.props.buttonClicked){
return(
<div>
<h1>{this.props.message}</h1>
<h1>{this.props.message}</h1>
</div>
);
}else{
return(
<div>
<h1>{this.props.message}</h1>
</div>
);
}
}
});
var Button = React.createClass({
render: function() {
return (
<div>
<input type="button" value= "add" onClick={this.props.onButtonClick} />
</div>
);
}
});
React.render(
<App />,
document.getElementById('app')
);
See the Pen React example by Takayuki Watanabe (@takanabe) on CodePen.
## 鉄の掟:ReactとjQueryの併用はしない
一般論というより自分のためのメモ。海外のサンプルコードを見ているとjQueryとReactを併用しているケースが見受けられるが、ReactとjQueryは使わない方が良い。ReactでDOMの状態を管理しているのに、DOMを操作する系のライブラリを導入するのはReactの優位性を失うどころか、足枷になりかねないからだ。Reactを使っている部分はjQueryは使わない。逆に、jQueryを使っている部分はReactは使わないと、両者の使用部分を明確にする必要がある。
## 所感
今回、Reactの概要、特徴を整理した。VDOMを生成するためのJSX記法には慣れが必要かも知れないが、個人的には学習コストは高くないと感じた。色々なアプリケーションを実装する中で良し悪しがあると思うので、しばらく使って見てそれらを洗い出して行きたい。ReactはFacebookのプロダクション環境で利用されているライブラリなので常にメンテナンスされているのも採用の敷居を下げる要因になるんじゃないかなと思う。今後日本でも多くのサービスで導入される予感がする。
## 参考
### 公式情報
* [Getting Started | React](https://facebook.github.io/react/docs/getting-started.html)
* [Conferences | React](https://facebook.github.io/react/docs/conferences.html)
* [Interactivity and Dynamic UIs | React](https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html)
### いろいろな人のReactとは
* [React概論 // Speaker Deck](https://speakerdeck.com/naoya/reactgai-lun)
* [6 Reasons Why We Love React.js | Syncano](http://www.syncano.com/reactjs-reasons-why-part-1/)
* [あなたがReactを使うべき理由 - mizchi's blog](http://mizchi.hatenablog.com/entry/2014/09/02/201728)
* [Ajaxを劇的に簡単にするReact.js – @masuidrive blog](http://blog.masuidrive.jp/2015/03/03/react/)
* [Reactを実際に使ってみた話が増えてきた - ワザノバ | wazanova](http://wazanova.jp/items/1582)
* [reactjs - React.jsとは - Qiita](http://qiita.com/koba04/items/4d13caf5ab4507974bf0)
### Reactの内部実装
* [Performance Calendar » React’s diff algorithm](http://calendar.perfplanet.com/2013/diff/)
### Reactを使ったSPAのサンプル集
* [Getting Started with React.js: Creating Material Design Components | Syncano](http://www.syncano.com/getting-started-reactjs-tutorial/)
* [enaqx/awesome-react · GitHub](https://github.com/enaqx/awesome-react)
### 木構造の差分検知の計算量比
* [algorithm - Detect differences between tree structures - Stack Overflow](https://stackoverflow.com/questions/5894879/detect-differences-between-tree-structures)
### 処理速度の比較記事
* [今話題のReact.jsはどのようなWebアプリケーションに適しているか? Introduction To React─ Frontrend Conference | HTML5Experts.jp](https://html5experts.jp/hokaccha/13301/)
* [React vs AngularJS vs KnockoutJS: a Performance Comparison](https://www.codementor.io/reactjs/tutorial/reactjs-vs-angular-js-performance-comparison-knockout)