脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

Reactで、jquery(ajax)内でsetStateしようとすると「this.setstate is not a function」って怒られて失敗する場合の対策

f:id:portaltan:20150804145645p:plain

問題

  • Reactを使っていてstateにsetしようとして普通にthis.setStateとかやっていると、this.setstate is not a functionってエラーが出るときがあります。
  • JavaScript的にどういうかはわかりませんが、Ruby的に言うとスコープが切り替わってself(=this)が変わっちゃった為に怒るエラーです。

調べてみた

英語でぐぐるとちょこちょこ情報が出てきますが、とりあえずは『thisが呼び出しているものが変わっちゃったので、bindingしてあげないとダメだよ』って言ってます

.bind(this)
  • 「bind」は関数内で参照できる this を指定のオブジェクトに束縛するメソッド
  • Javascriptでは、オブジェクトのメソッドはオブジェクトに束縛されているのではなく、その時々のコンテキストにおいて実行される
thisの確認

console.log(this);でthisの内容を確認してみましょう。

  • reactが使える場所では
R…s.c…s.Constructor {props: Object, context: Object, state: Object, refs: Object, _reactInternalInstance: ReactCompositeComponentWrapper}
	_reactInternalInstance: ReactCompositeComponentWrapper
	・
	・
	・
	state: Object
	__proto__: ReactClassComponent    // <==  重要!!
		__reactAutoBindMap: Object
		・
		・
		・
		setState: (partialState, callback)
			arguments: (...)
			caller: (...)
			length: 2
			name: ""
			prototype: ReactComponent.setState
			__proto__: ()
			<function scope>
		__proto__: Object
  • Reactが使えない場所では
Window {top: Window, location: Location, document: document, window: Window, external: Object}
	・
	・
	・
	__proto__: Window  // <= ReactClassComponentじゃない

対策

jquery単体の場合
$.get(URL, function(res){
    this.setState({response: res});
}.bind(this));  // <= Binding!
Ajaxの場合
$.ajax({
     url: URL,
     type: 'POST',
     data: data,
     cache: false,
}).done(function(res){
     this.setState({response: res})
}.bind(this)).fail(function(){  // <= Binding!
    this.setState({response: 'Ajax Request was failed '})
}.bind(this));  // <= Binding!
メソッドへ渡す場合
var fnc = function testMethod(arg1, arg2) {
    res = ${処理の結果}
    this.setState({{response: res}})
}

var Test = React.createClass(
    fnc.bind(this)('hogehoge', { foo: 'bar', key: 'value' });  // <= Binding!
}