Reactjsのチュートリアルを読んで浮かんだ疑問とそれに対する答え

[Reactjsのチュートリアル](http://facebook.github.io/react/docs/tutorial.html)を読んでみて、大雑把なReactjsの使い方を把握したのですが、疑問に思った点がいくつかあったので調べてみました。

# 前提

筆者のReactjs力がどれくらいかと言うと

- 存在は知ってたが、中身は全く知らなかった
- [VirtualDom - なぜ仮想DOMという概念が俺達の魂を震えさせるのか](http://qiita.com/mizchi/items/4d25bc26def1719d52e6)を読んだ

だけの状態です。つまりコンセプトは知っているが、細かい話は何も知らなかった状態です。その状態で前述の[チュートリアル](http://facebook.github.io/react/docs/tutorial.html)を読んだ感じです。

# 疑問

## Q. どうやってcomponentの解決をしている？

```js
var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        Hello, world! I am a CommentBox.
      </div>
    );
  }
});
React.render(
  <CommentBox />,  // この部分
  document.getElementById('content')
);
```

`CommentBox` は単なる変数の名前なので、reactjs側からは `CommentBox` という名前のcomponentがいることは分からないはずなのに、 `React.render` する時に `<CommentBox />` と書けるのは何故だろう？

### A. JSX展開後に `CommentBox` 変数を直接使っている

先ほどのコードをJSXの翻訳機に通すと次のようなコードになります。

```js
var CommentBox = React.createClass({displayName: 'CommentBox',
  render: function() {
    return (
      React.createElement('div', {className: "commentBox"},
        "Hello, world! I am a CommentBox."
      )
    );
  }
});
React.render(
  React.createElement(CommentBox, null), // ここ
  document.getElementById('content')
);
```

見れば分かるように `CommentBox` 変数を直接使っています。チュートリアル中では特にスコープの話は出てきませんが、componentを使う場合はそのクラスが参照できなければいけないようです。

というわけなので、こんな感じでモジュール化しても大丈夫そうです。

```js
define('CommentBox', ['react'], function (React) {
  return React.createClass(/* .. */)
});
```

```js
require(['react', 'CommentBox'], function (React, CommentBox) {
  React.render(
    <CommentBox />,
    document.getElementById('content')
  );
});
```

## Q. propsとstateの違いは何？

各componentはpropsとstateを持っています。これらは両方共 `render()` 時に使うのが主な使い方のようだけど、わざわざ2種類用意しているのは何故？

### A. propsはimmutable、stateが変更されると再描画される

- [Performance Calendar » React’s diff algorithm](http://calendar.perfplanet.com/2013/diff/)

propsは変更しない（immutable）が、stateはそうではないとのこと。

Reactjsではアプリケーションをcomponentの階層として実装し、全体としては木構造になります。あるcomponentのstateが `setState()` によって変更されると、Reactjsはそのcomponentにdirtyフラグを立てます。

![4.png](https://qiita-image-store.s3.amazonaws.com/0/153/1d7593ec-5ae3-30d9-9129-8eeb657254fb.png)

そして処理が終わった段階でdirtyなcomponentとその子供達を全てrenderします。

![5.png](https://qiita-image-store.s3.amazonaws.com/0/153/46e1741a-7aec-2e51-e3cc-536639336c7b.png)

こうすることで新しい仮想DOMを構築するコストを極限まで減らしています。また仮想DOMの差分を計算する際も、変更されている可能性があるcomponentに絞って計算すればいいことになります。

## Q. propsとstateの使い分けは？

### A. いくつかのチェックリストがあるのでそれを参考にする

- [Thinking in React | React](http://facebook.github.io/react/docs/thinking-in-react.html#step-3-identify-the-minimal-but-complete-representation-of-ui-state)

1. 親から渡されるものなら、それはおそらくstateではない
2. 時間とともに変化するものでないなら、それはおそらくstateではない
3. 他のstateやpropsから計算できるなら、それは確実にstateではない

stateは一般的に親で管理され、それを使って子にpropsが渡されるようです。なので、stateを管理すべきcomponentは

- そのstateを使って描画される全てのcompnentの共通の親
- もしくはそれより上のcomponent
    - いいのが無い場合はstateを保持するだけのcomponentを上位階層に作ってもいい

## Q. component終了時にメモリリークを防ぐには？

例えば `Backbone.View` からあるHTML要素を参照していて、その要素がReactjsによって削除された場合、そのviewオブジェクトからの参照を消さないと、メモリリークが発生してしまいます。

HTML要素に直接紐付いているイベントハンドラだったら、 `componentWillUnmount` 時に頑張れば終了処理を実行できそうですが、単なるJSオブジェクトの場合はどうすればいいの？

### A. viewオブジェクトの作成から終了までをcomponentにやらせる

そもそもReactのあずかり知らないところでHTML要素への参照を保持することが間違っているのだろうと思います。つまり `Backbone.View` を使いたいなら、そのインスタンスは `componentDidMount` で作成して参照をcomponentにもたせておき、 `componentWillUnmount` で削除する訳です。

```js
var CommentBox = React.createClass({
  componentDidMound: function () {
    this.view = new Backbone.View({ el: this.refs.foo.getDOMNode() });
  },
  componentWillUnmount: function () {
    this.view.remove();
  },
  render: function() {
    return (
      <div className="commentBox" ref="foo">
        Hello, world! I am a CommentBox.
      </div>
    );
  }
});
```

# おわりに

Reactjsは思想・使い方を含めて非常にシンプルで、理解しやすい印象でした。面倒な箇所をJSXに押し付けているので、JSレベルでは、書いてあることとその挙動が把握しやすくなっているのがいいですね。