React v0.13 RC - 気になる点を検証

# はじめに
　react.jsのv0.13 RCが先日(2015.02.24)発表されました。と、思ってたら昨日(2015.03.03)v0.13 RC2が発表されていますね。変更点は文章だけで実際のコードの例が無いので初心者の筆者にはいまいちわからなかったです。ということで「多分こういうことかな？」というコードを現在の安定版(v0.12.2)と比較して結果をまとめたいと思います。グダグダとブログで書いているバージョンは以下にて参照可能です。本記事では簡潔に挙動の違いだけに触れます。**仕様理解が不足している点や、誤っている点があるかと思いますので、コメント等でご指摘・ご連絡いただければ幸いです。**

* [React v0.13 RC での変更点 – propsの警告](http://t.co/DHh5sikWac)
* [react.js v0.13 RC – staticsの中の’this’に注意](http://t.co/eeqKauszzf)
* [react.js v0.13 RC – unmount済みComponentでsetStateまたはforceUpdate](http://t.co/XIKlvExDDl)
* [react.js v0.13 RC – setStateで関数を渡せるようになった](http://t.co/fJB3JdDwvZ)

# propsをMutateした場合の警告追加
　react.jsでコンポーネントの`props`を変更した場合に`Warning`が表示されるようになりました。以下のようなコード（を書くことはまずありえませんが...）があったとします。

```js
var ExampleApplication = React.createClass({

	render: function() {
		// ここでthis.props.nameを無理矢理変更
		// 出力結果は「mutated name!」になります
		return <p>{this.props.name = 'mutated name!'}</p>;
	}
});
var start = new Date().getTime();
React.render(
	<ExampleApplication name='kenfdev' />,
	document.getElementById('container')
);
```

v0.13rcより前は特に何もありませんでしたが、v0.13rcからはdevelopment mode時のみではありますが、以下の警告が表示されます。

> Warning: Don't set .props.name of the React component <ExampleApplication />. Instead, specify the correct value when initially creating the element.


# staticsの'this'
　コンポーネントで定義できる`statics`がv0.13rcからコンポーネントに自動でバインドされなくなります。

```js
var MyComponent = React.createClass({
	// static method
	statics: {
		message: 'Hello',
		staticMethod: function() {
			// < v0.13rc：thisはコンポーネント(MyComponent)に自動バインド
			// v0.13rc：thisはコンポーネントに自動バインドされない
			return this.message;
		}
	},
	render: function() {
	}
});

// messageを持つオブジェクトを準備
var caller = {
	message: 'Hey!'
};

// Greetings component
var Greetings = React.createClass({
	render: function () {
		// < v0.13rc：staticMethodはMyCompoentにバインドされているので出力結果は「Hello」
		// v0.13rc：staticMethodはMyComponentにバインドされておらず、呼び出し元をcallerに明示的に設定している為出力結果は「Hey!」
		return <div>{MyComponent.staticMethod.call(caller)}</div>
	}
});

React.render(<Greetings></Greetings>, document.body);
```

# アンマウントされたコンポーネント内でのsetState、forceUpdate
　react.js v0.13rcからアンマウント済みのコンポーネントでsetState、forceUpdateが呼ばれたとしても、例外`throw`するのではなく`Warning`で留まる様になった。PromiseによってResolveされるのが大きく遅延した場合などにコンポーネントが先にアンマウントされてしまい、結果的に後になって例外が発生してしまう現象をどうにかしてほしい、という要望に答えてくれたみたいです。以下、`setState`をアンマウント後のコンポーネントで呼び出した例。

```js
// Helloコンポーネントを2秒後にアンマウントさせる為の設定
var timeoutBeforeUnmount = 2000;

// The Hello Component
var Hello = React.createClass({          
    getInitialState: function() {
        return {message: 'World'};
    },
    componentDidMount: function() {
        var self = this;
        setTimeout(
            function() {
                // setStateを呼び出す
                self.setState({message: 'again to the World'})
            },
            // Helloコンポーネントの1秒後にsetStateを発火させる
            timeoutBeforeUnmount + 1000
        );
    },
    render: function() {
        return <div>Hello {this.state.message}</div>;
    }
});
 
React.render(<Hello />, document.getElementById('container'));

// Helloコンポーネントを2秒後にアンマウント
setTimeout(function() {React.unmountComponentAtNode(document.getElementById('container'))}, timeoutBeforeUnmount);
```

以下、結果の比較

```bash
# react.js < v0.13rc　例外発生
Uncaught Error: Invariant Violation: replaceState(...): Can only update a mounted or mounting component.

# v0.13rc <= react.js　警告止まり
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.
```

# setStateに関数
　react.js v0.13rcからsetStateに関数を渡せるようになりました。何がうれしいのかというと、これは筆者の浅はかな知識で書きますが、同じ関数内で`state`に変更を加える場合、`state`が即時反映されないが為に意図した結果にならないシチュエーションがあります。

```js
var Hello = React.createClass({
    getInitialState: function(){
        return {count:0};
    },
    handleClick: function(e) {
        // countをインクリメント
        this.setState({count: this.state.count + 1});
        
        // 同一関数内で再度インクリメント
		// 2になってくれるかと思いきや、this.state.countは即時反映されるわけではないので、上のsetStateも下のsetStateも「0 + 1」を実行してしまい、結果は「1」になってしまう。
        this.setState({count: this.state.count + 1});
    },
    render: function() {
        return (<div onClick={this.handleClick}>
        Click Me and the Count will try to increment by 2 but will fail!<br />
        Count: {this.state.count}</div>);
    }
});
 
React.render(<Hello />, document.body);
```

 この対策としては`_pendingState`を使う手法がある様です。`handleClick`の中身が以下の場合は出力結果は2ずつインクリメントされます。

```js
this.setState({count: this.state.count + 1});
        
// 'this._pendingState'なら即時反映された値にアクセスできる
this.setState({count: this._pendingState.count + 1});
```

　こんなことをしなくて済むようにv0.13rcからは`setState`に関数を渡して最新状態の`state`にアクセスできるようになっています。また、高度な`state`の変更もこれでできるようになりそうですね。

```js
var Hello = React.createClass({
	getInitialState: function(){
		return {count:0};
	},
	handleClick: function(e) {
		// setStateに関数を渡すことが可能。この計算は「0 + 1」となる
		this.setState(function(state,props) {return {count: state.count + 1};});
		// 最新状態のstateにアクセス可能なので、この計算は「1 + 1」となる
		this.setState(function(state,props) {return {count: state.count + 1};});
	},
	render: function() {
		return <div onClick={this.handleClick}>Count: {this.state.count}</div>;
	}
});

React.render(<Hello />, document.body);

```