Node.jsもES2015も使わないReact入門

# この記事について

プロダクト開発でReactを使い始めてそろそろ半年ほどになります
やっといい感じに扱えるようになってきたので、ノウハウを記事にしていこうかなと思っています

Reactって使い始めると便利なのですが、一つ大きな問題があります
そう、それは導入障壁が大きすぎること
Node入れて、Babel導入してJSX/ES2015でコーディングして、タスクランナー導入してビルド自動化して、Redux導入して...
巷のReact記事を読むとこんな感じの内容ばかりで思わず萎縮してしまうことでしょう

というわけで、この記事では「React使ってみたい、でもNodeとかES2015とかよくわかんない」って人向けのReact入門講座を進めていこうと思います
いきなりReact+Reduxのサンプルが出てきたりしてちょっと混乱してる方や、
JSX使ってBabelでコンパイルしてるけどReactの基礎的なところからやり直したいって方もぜひどうぞ
この記事を読めば、Reactと言えど結局はただのJSで実装されていることがわかると思います
なるべく余分な要素をそぎ落として、React自体について考える手助けになることを願っています

# Reactを使う準備をしよう

## 雛形のhtmlファイルを用意する

基本的にこの記事ではReactの使い方自体にフォーカスしていきたいので、環境構成は最小限に抑える方針で進めていきます

まずは、https://facebook.github.io/react/ からReact.jsをダウンロードしましょう
今回はReact v0.14.7を利用します
(余談ですが、Reactはv0.14.7の次からv15.x.xという形にバージョンの取り方が変わりました
確認はしていませんが、この記事に載っているサンプルならv15系でも動くと思います)

もしくは、[cdnjs](https://cdnjs.com/) などを利用しましょう
https://cdnjs.com/libraries/react/0.14.7
本記事ではこちらの方法で進めていきます

では、雛形となるhtmlファイルを作成します

```html
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Minimal React</title>
  </head>
  <body>
    <div id="app"></app>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.js"></script>

    <script>
      // ここにJS書いていくよ
    </script>
  </body>
</html>
```

**注意点**として、`react.js`に加えて`react-dom.js`も読み込む必要があります

## とりあえず、何か表示してみよう

次に恒例の`Hello, World`でもやってみましょう
最後のscriptタグの中に次のコードを加えてください

```js
rootElement = React.createElement('div', {}, "Hello, World")
ReactDOM.render(rootElement, document.getElementById('app'))
```

`Hello, World`と表示されたでしょうか
表示されれば準備OKです

# Reactで自在にDOMを生成する

さて、まずは先ほどの`Hello, World`のコードを見てみましょう

`React.createElement`は要素を生成するAPIです
第一引数にhtml要素名、第二引数にhtml属性、第三引数以降に要素の中身を指定します
React本家のリファレンスを見たら、戻り値は`ReactElement`と呼ばれているようなので、この記事でも以降ReactElementで統一したいと思います

`React.createElement`で生成されたReactElementは、`ReactDOM.render`でDOMにアタッチされます
第一引数にDOMにアタッチするReactElement、第二引数に実際のDOM内に準備したコンテナを指定します
つまり、今回の場合では

```html
<div id="app">
  <div>Hello, World</div>
</div>
```

みたいな感じんなるわけですね
ここの読み替えはすっとできるように感覚に落とし込んでいきましょう
ここまでが、Reactの第一歩目になります

次に、scriptタグ内を書き換えてもう少し複雑なDOMツリーを生成してみましょう

```js
rootElement = React.createElement('div', {},
  React.createElement('h1', {}, 'Brand'),
  React.createElement('ul', {},
    React.createElement('li', {},
      React.createElement('a', { href: '/about' }, 'About')
    ),
    React.createElement('li', {},
      React.createElement('a', { href: '/news' }, 'News')
    ),
    React.createElement('li', {}, 
      React.createElement('a', { href: '/contact-us' }, 'Contact us')
    )
  )
)
ReactDOM.render(rootElement, document.getElementById('app'))
```

ヘッダーのグローバルナビゲーションをイメージして作ってみました
ポイントとしては、`React.createElement`の第三引数以降にはいくつでもReactElementまたは文字列を渡すことができる点でしょうか
つまり、`createElement`は上記のように入れ子みたいにして書けるわけですね

さて、上の結果生成されるhtmlはどのようになるでしょうか？

```html
<div id="app">
  <div>
    <h1>Brand</h1>
    <ul>
      <li><a href="/about">About</a></li>
      <li><a href="/news">News</a></li>
      <li><a href="/contact-us">Contact us</a></li>
    </ul>
  </div>
</div>
```

こんな感じですね

# コンポーネント - 自作の要素を用意する

だいたいReactの感覚はつかめてきたでしょうか
次は、複数のReactElementを組み合わせた自作要素を定義してみましょう
Reactではコンポーネントと呼ばれるやつですね
コンポーネントを定義することで、要素の再利用が可能になります

早速、先ほどのナビゲーションをコンポーネント化してみましょう

```js
var GlobalNavigation = React.createClass({
  render: function() {
    return React.createElement('div', {}, 
      React.createElement('h1', {}, 'Brand'),
      React.createElement('ul', {}, 
        React.createElement('li', {}, 
         React.createElement('a', { href: '/about' }, 'About')
        ),
        React.createElement('li', {}, 
         React.createElement('a', { href: '/news' }, 'News')
        ),
        React.createElement('li', {}, 
         React.createElement('a', { href: '/contact-us' }, 'Contact us')
        )
      )
    )
  },
})

var rootElement = React.createElement(GlobalNavigation, {})
ReactDOM.render(rootElement, document.getElementById("app"))
```

`createClass`はコンポーネントを定義するためのAPIです
(ES2015導入環境では`class`構文を使い`React.Component`を継承します)
第一引数にオブジェクトを指定します
戻り値はReactClassと呼ばれているようです

第一引数について、`render`というメソッドを定義してやります
読んで字のごとくコンポーネントの描画用のメソッドです
`render`内で`return`したReactElementがこのコンポーネントの中身となります

続いて、`React.createElement`に`MyComponent`を渡します
先ほどまでは`'div'`などの要素名を指定していましたが、コンポーネントを定義すると要素名と同様にReactClassを第一引数に指定することができます

コンポーネント化を行うことで、コンポーネントの再利用が可能になります
例えば、以下のような例を考えてみましょう

```js
rootElement = createElement('div', {},
  React.createElement(GlobalNavigation, {}),
  React.createElement(SideBar, {}),
  React.createElement('div', {} 'This is main contents'),
  React.createElement(Footer, {})
)
```

こんな形でナビゲーションやフッターなどを共通化できるわけですね
便利！

# 状態変化のあるアプリケーションを作る

さて、いよいよアプリケーションっぽいものを作る準備が整いました
ここではReactにおいて状態を管理するための方法を紹介します
簡単なカウンターを作ってみましょう
仕様としては+1ボタンを押すとカウントアップ、-1を押すとカウントダウンといったところでしょうか

```js
var CounterApp = React.createClass({
  getInitialState: function() {
    return {
      count: 0,
    }
    // 2016/05/09 訂正
    // コメントアウトした部分は間違ってました
    // 上記のように記述するのが正解です
    // this.state = {
    //   count: 0,
    // }
  },
  render: function() {
    return React.createElement('div', {},
      React.createElement('div', {}, "count: " + this.state.count),
      React.createElement('div', {
        onClick: function() {
          this.setState({
            count: this.state.count + 1
          })
        }.bind(this),
      }, "+1"),
      React.createElement('div', {
        onClick: function() {
          this.setState({
            count: this.state.count - 1
          })
        }.bind(this),
      }, "-1")
    )
  }
})

var rootElement = React.createElement(CounterApp, {})
ReactDOM.render(rootElement, document.getElementById("app"))
```

ちょっと今回は説明することが多いです

まずは`CounterApp`というReactClassを作成しています

`CounterApp`に`getInitialState`というメソッドを定義しています
Reactでは状態変数のことをstateと呼んでいます
その初期値を返すのが`getInitialState`というわけですね
今回はカウンターの値を保持するための`count`プロパティの初期値を0にしています
ここで初期化した`state`は、ReactClass内では`this.state`として参照することができます

`render`メソッドを見てみましょう
`"count: " + this.state.count`として先ほど初期化したstateを参照しています
また、その下にボタン用のdiv要素を二つ用意しています
それぞれ第二引数に`onClick`ハンドラを指定しています
Reactではこのようにしてイベントの追加ができるわけですね
イベントハンドラの中では`this.setState`というメソッドを呼んでいます
これはstateを更新するためのメソッドなのですが、`this.setState`が呼ばれるとReactClassは仮想DOMと呼ばれる仕組みを利用して自身の状態を自動で更新します
詳細は後ほど述べようと思いますが、とりあえず今は「状態更新するには`setState`」と覚えてください
※ `this.state`の値を直接変更してはいけません

このサンプルを実際に実行していただければ、クリックするだけで自動でDOM状態が更新されることが確認できると思います
これはクリックによって`setState`が実行されstateが更新され、その更新に基づいて再びReactClassがrenderメソッドを実行しDOM更新を行ってくれるためです
このようにDOM操作をReactが隠匿してくれるおかげで、我々は状態の管理に集中することができるのです

この記事で掲載するサンプルはこれで最後にしようと思います
`state`とは別に`props`なども説明したいのですが、今回はここまでとします
最後に少し仮想DOMについてお話をして終わりにしましょう

# 仮想DOMとは

先ほども少し触れた仮想DOMですが、1, 2年ほど前(ちょっと正確にはわからないです)に登場し非常に注目を集めてきました
それは、今までのフロントエンドの状態管理へのアプローチを一変させるポテンシャルを持っていたからです

かつてのフロントエンドは、DOMイベントなどが発生するたびに**DOMの一部を書き換えて**状態を変更するという実装が主流でした
代表例はjQueryですね
しかし、この実装方法には「DOM自身が状態を持ってしまうので、状態が様々な場所に散り散りになり管理が大変」という問題がありました
SPA(Single Page Application)などの需要が高まるに連れて、この問題はより深刻になりフロントエンドエンジニアを苦しめていきます
特定の状態の時にしか発生しないバグなどの温床ですからね
フロントエンドな方なら一度は頭を悩まされたのではないでしょうか

このような問題を解消しようと、状態を一箇所に集めておき状態の更新が起こるたびに**DOM全体を描画し直す**という実装をしようという流れが生まれてきます
しかし、想像に難くない通り、ただでさえ重いDOM操作をページ全体で行うのはパフォーマンス的に考えて現実的ではありません

そこで、**仮想DOM**の出番です
仮想DOMとはJS上でDOMのツリー構造を再現したものです
これが全体更新を可能にするわけです
状態の更新が発生すると、Reactはまず実際のDOMに変更を加えるのではなく、仮想DOM上でツリー構造を再現します
そして、更新前の仮想DOMツリーと比較しその**差分だけ**を抽出します
そのあと、差分のみの変更を実際のDOMに対して行います
つまり、Reactでは全体更新を行っても、いい感じに最小のDOM操作だけを行ってくれるわけです
この仮想DOMの登場によってフロントエンドもページ全体を毎度書き換えるというアプローチが可能になったわけですね

さらに全体更新というアプローチが可能になったことで、我々は細かいDOM操作については考える必要がなく、状態からDOMを生成することだけに集中すればよいことになります
Reactにおいてはコンポーネントがこの役割を担います
コンポーネントはstateからDOMツリーを生成する**ある種の関数**のようなものとして解釈することができます
イメージとしては`state => (f) => DOM`みたいな感じですかね
stateをコンポーネントに通すとDOMが出来上がる的な感覚だと自分は思っています
あるいは、コンポーネントを`PHP`や`Ruby`の`erb`テンプレートなどのように考えてもいいと思います
状態を与えてあげたらHTMLドキュメントを生成してくれる点でコンポーネントと本質的には同じです
ただし、コンポーネントは単純にドキュメントを生成するのに比べてイベントのバインドなども行ってくれるわけですが

こういったわけで、仮想DOMによって今まで不可能だった**全更新**が可能になりフロントエンドに新たな可能性が生まれたのです
こうした中で生まれたフロントエンドアーキテクチャの一つが`Flux`だったりするわけですね
(`Flux`実装もたくさんあるので自分もあんまり追えてないです...
というか、全般的に流れが速すぎてフロント界隈に追いつけてない感じがします)

# 最後に

ここで紹介した内容ぐらいを押さえておけば[本家のReactチュートリアル](https://facebook.github.io/react/docs/tutorial.html)なんかを見ても多分ついていけるのではないでしょうか
ちなみに、今回紹介したぐらいのコードでJSからどんなDOM構造が出来上がるか変換ができれば、JSXなんて1ミリも怖くないですし、むしろ脳内変換する手間が省けるので便利です
まだまだこれからAjaxによる非同期処理が入ってきたり、より複雑なアプリケーションを作る上でどんな設計をしていくのかは考えなければならないことがたくさんあるのですが、そのあたりは巷のいろんなサンプルを見たり実際に試行錯誤していくしかないかなと思います
というわけで、この記事がReactに入門する上での手助けになることを願ってこの記事を締めくくりたいと思います