ReactのComponent.setStateによるstateの書き換えは非同期処理である


ReactのComponent.setStateによるstateの書き換えは非同期処理である

Reactはパフォーマンス最適化のために、setStateが呼ばれたからと言って、実際のstateを即書き換えるわけではありません。

stateの更新はReact内部でよろしくまとめられて非同期で行われます。

例えば、以下のコードはうまく動いてくれません。

// this.state.hoge = 'fuga'の状態とします。

this.setState({
hoge:'piyo';
});
console.log(this.state.hoge);//出力されるのはpiyoではなくfuga


困りそうなケースと対応策


state変更後、後続の処理でstateの値を参照して処理したい

this.setState({

hoge:'piyo';
});

fuga();//fugaの中でthis.state.hogeが参照される

気を付けていないと意外と書いてしまうかも知れません。


対応策

同期処理が必要な場合はstate経由は不適切なので、素直にfugaの引数として渡しましょう。


インクリメントなど前のstateに依存する処理

this.setState({

hoge:this.state.hoge + 1;
});

こんな感じの元のstateの値に依存する処理の場合、

連続で実行されると想定通りに動いてくれません。

例えば、this.state.hoge=3の状態で連続して上記の処理を2回実行すると、

一回目はhoge: 3 + 1 と想定通りに動いてくれますが、

二回目までの間にthis.state.hogeが4に切り替わらないので、

二回目もhoge: 3 + 1 をsetStateの引数として渡してしまいます。

こうなるとReactは「 hoge:4が2回来たけど一回でいいな。」と考えてしまうので

hogeは5になりません。


対応策

functionをsetStateの引数として渡しましょう。

this.setState((state,prop) => {

return {hoge:state.hoge + 1};
});

このようにstateとpropを引数に取ると、stateが切り替わってから関数を実行してくれるので、

前のstateに依存する処理を書いても正しくstateを変更できます。


stateの変更によってComponentが再描画されてから処理したい場合

setStateの第二引数にコールバック関数を渡しましょう。


まとめ


  • setStateしてもthis.stateはすぐには書き換わらない

  • 同期処理をしたい場合は素直に引数で

  • インクリメント系処理は関数をsetStateに渡す

  • 描画処理まで一通り終わってからの場合はコールバック関数