React.jsのAddonについて

今回はAddonについて紹介していきたいと思います。

Addonには本体に入れるほどではないけど、あると便利なmixinやテストのutil、パフォーマンス計測のtoolなどが入っています。

# 使い方

使う時は、Addon入りのreactをrequireするかAddon入りのJSを読み込みます。

```js
var React = require('react/addons');
```

or

```html
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.12.1/react-with-addons.js"></script>
```

# Add-ons

## TransitionGroup and CSSTransitionGroup

AnimationをさせるためのAddonです。これについては明日のAdvent Calendarで紹介したいと思います。


## LinkedStateMixin

こちらは以前にも紹介したとおりFormを扱うときに2wayデータバインディングのように簡潔に書くためのMixinです。

こちらを見てください。

http://qiita.com/koba04/items/40cc217ab925ef651113#linkedstatemixin


## ClassSet

classNameの指定をわかりやすくやるためのAddonです。

`{ className: boolean}`の形式で指定することが出来て、booleanがtrueのclassNameが適用されます。

Angular.jsなど他のフレームワークでもあるやつですね。

```js
var classSet = React.addons.classSet;

var Hello = React.createClass({
  getInitialState() {
    return {
      isWarning: false,
      isImportant: false
    };
  },
  toggleWarning() {
    this.setState({ isWarning: !this.state.isWarning });
  },
  toggleImportant() {
    this.setState({ isImportant: !this.state.isImportant });
  },
  render() {
    var style = classSet({
      'is-warning': this.state.isWarning,
      'is-important': this.state.isImportant
    });
    return (
      <div>
        <button onClick={this.toggleWarning}>warning</button>
        <button onClick={this.toggleImportant}>important</button>
        <p className={style}>( ´ ▽ ` )ﾉ</p>
      </div>
    );
  }
});
```

http://jsfiddle.net/koba04/4Le38o0n/1/


## TestUtils

これはReact.jsのテストをするときに便利なAddonです。development onlyです。

* clickイベントなどをシュミレートするTestUtils.Simurateや`isElementOfType`や`isDOMComponent`などComponentの状態を確認できるような関数まで色々あります。

```js
var node = this.refs.input.getDOMNode();
React.addons.TestUtils.Simulate.click(node);
React.addons.TestUtils.Simulate.change(node, {target: {value: 'Hello, world'}});
React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter"});
```

テストについてはまた別途紹介する予定なのでその時に書きたいと思います。


## cloneWithProps

あんまり使いたい場面が思い浮かばないのですが、あるComponentから異なるPropによる新しいComponentを作りたいときに使うAddonです。

```js
var cloneWithProps = React.addons.cloneWithProps;

var Item = React.createClass({
  render: function() {
    var text = this.props.text + (this.props.index != null ? ":" + this.props.index : '');
    return <div>{text}</div>
  }
});

var Loop = React.createClass({
  render: function() {
    var items = _.map(_.range(this.props.count), function(i) {
      return cloneWithProps(this.props.children, { key: i, index: i });
    }.bind(this));
    return <div>{items}</div>
  }
});

React.render(<Loop count="10"><Item text="hoge" /></Loop>, document.body);

```

無理やりchildrendを指定回数繰り返すComponentを作ってみました...


## update

ObjectをImmutableに操作するためのAddonで、後述の`PureRenderMixin`や`shouldComponentUpdate`を単純なPropとStateの比較として実装し高速化したいような場面で組み合わせて使うと便利です。

```js
var update = React.addons.update;

var obj = {
  list: [1,2,3],
};

var obj2 = update(obj, {
  list: {
    $push: [4]
  }
});

console.log(obj2.list);     // [1,2,3,4]
console.log(obj === obj2);  // false
```


ちなみにfacebookは別途Immutable.jsというのを作ってるのでそっちを使うとこんな感じになります。


```js
var obj = Immutable.Map({
    list: Immutable.List.of(1, 2, 3)
});

var obj2 = obj.set('list', obj.get('list').push(4));

console.log(obj2.get('list').toArray()); // ['a','b','c','d']
console.log(obj === obj2); // false
```

http://facebook.github.io/immutable-js/


## PureRenderMixin

パフォーマンスを高速化するためにMixinです。
実装を見た方が早いとおもうので紹介しておきます。

```js
var ReactComponentWithPureRenderMixin = {
  shouldComponentUpdate: function(nextProps, nextState) {
    return !shallowEqual(this.props, nextProps) ||
           !shallowEqual(this.state, nextState);
  }
};
```
https://github.com/facebook/react/blob/master/src/addons/ReactComponentWithPureRenderMixin.js

shallowEqualはこんな感じになっています。ネストされた値までは考慮せず単純に比較しています。

```js
function shallowEqual(objA, objB) {
  if (objA === objB) {
    return true;
  }
  var key;
  // Test for A's keys different from B.
  for (key in objA) {
    if (objA.hasOwnProperty(key) &&
        (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
      return false;
    }
  }
  // Test for B's keys missing from A.
  for (key in objB) {
    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}
```
https://github.com/facebook/react/blob/master/src/utils/shallowEqual.js


## Perf

パフォーマンス計測を行うためのAddonです。development onlyです。

`Perf.start()`と`Perf.stop()`で計測したい箇所を囲んで統計を取ることが出来ます。

```js
    React.addons.Perf.start();
    this.setState({ items: items }, function() {
      React.addons.Perf.stop();
      React.addons.Perf.printInclusive();
    });
```

Item Componentを100個追加する計測のサンプルを用意したので、どんな感じで表示されるのか見るとイメージしやすいと思います。
(DeveloperConsoleに表示されます)

http://jsfiddle.net/koba04/Lpeubepw/1/

計測の数値がものすごく小さな値の場合は無視されます。


### printInclusive

計測中のComponentの処理に掛かった時間をconsole.tableでわかりやすく出力してくれます。

![printInclusive](https://qiita-image-store.s3.amazonaws.com/0/4677/92b01aad-fe42-1a08-a62f-7dbee71234fa.png)


### printExclusive

Componentの処理に掛かった時間がより詳細にconsole.tableで出力されます。

![printExclusive](https://qiita-image-store.s3.amazonaws.com/0/4677/7de5b7f7-1cd7-9da4-c367-fcb05d644469.png)


### printWasted

実際のレンダリング処理以外に掛かった時間をconsole.tableで出力します。
`shouldComponentUpdate`を適用する場所を探すための手かがりとしても便利です。

![printWasted](https://qiita-image-store.s3.amazonaws.com/0/4677/26ed25bf-1d70-0877-334d-bbbac219a62d.png)



### printDOM(measurements)

DOMへの追加・削除をconsole.tableで出力します。

![printDOM](https://qiita-image-store.s3.amazonaws.com/0/4677/9f0d9e71-4032-c32b-9d5f-7dd4764e64af.png)


### getLastMeasurements

計測情報をObjectの形式で取得することができます。
serverに送信するなどして使いたい場合や、上で紹介した各メソッドに渡すことも出来るのでいくつか計測して最後にまとめて出力などといった使い方もできます。


-----

今回はAddonについて紹介しました。
明日は、Addonの中にあるAnimationについて書きたいと思います。