Reactで、jquery(ajax)内でsetStateしようとすると「this.setstate is not a function」って怒られて失敗する場合の対策
問題
- 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! }