Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

setStateの非同期処理

先日ご紹介したReact nesを用いてチャットボット的なものを作成中!!
elsammit-beginnerblg.hatenablog.com

そこで、ReactのsetStateに対する非同期処理に躓いたので備忘録として残しておきたいと思います。
f:id:Elsammit:20210206185459p:plain



■setStateは非同期処理

この記事をご覧になっている方はすでにご存じかと思いますが、setStateは非同期で実行されます。

例えば、こちらのようなコードを実行した場合、

constructor (props) {
    super(props);
    this.state = {
        buf:"hello"
    };
}

ClickTest = () =>{
    this.setState({
      buf:"hogehoge"
    })
    console.log(this.state.buf);
}

ログ出力されるのは"hogehoge"ではなく、"hello"になります。

非同期処理で動いているため、反映される前に次処理が走ってしまいます。
このため、

constructor (props) {
    super(props);
    this.state = {
        buf:"hello"
    };
}

ClickTest = () =>{
    this.setState({
      buf:"hogehoge"
    })
    this.DoComp();
}

DoComp = () =>{
  if(this.state.buf ==="hogehoge"){
    console.log("OK");
  }else{
    console.log("NG");
  }
}

のような処理を実行してしまうと、本来は"OK"のログが出るように処理をしたいはずなのに、NG側の処理となってしまいます。
これは注意しないといけませんね。

■対処方法

では、どうすれば回避することが出来るのか。
まずはコードを記載してしまいます。

ClickTest = () =>{
    this.setState({
      buf:"hogehoge"
    },
    this.DoComp
    )
    //this.DoComp();
}

DoComp = () =>{
  if(this.state.buf ==="hogehoge"){
    console.log("OK");
  }else{
    console.log("NG");
  }
}

setState関数ですが、第1引数がステートオブジェクトに対して第2引数はコールバック関数が定義できるようです。
このため、

    this.setState({
      buf:"hogehoge"
    },
    this.DoComp
    )

というように、setState関数の第2引数にDoComp関数を定義すればOKです。
こちらを実行すると、bufに"hogehogeがセットされてからコールバック関数としてDoComp関数がコールされるので、
想定通り、OKログが出力されるように処理することが可能になります。

さらに、

ClickTest = () =>{
    this.setState({
      buf:"hogehoge"
    },() =>{
      if(this.state.buf ==="hogehoge"){
        console.log("OK");
      }else{
        console.log("NG");
      }
    })
}

というように記載しても同様にOKログが出力されるように処理させることが可能になります。

もしsetStateで変数への値セット後に処理を実行したい場合にはこのように処理させる必要があります。

■補足

実はrenderはsetStateによる値セットを待ってから処理を実行しております。
例えば、

ClickTest = () =>{
    this.setState({
      buf:"hogehoge"
    })
    console.log("ClickTest:"+this.state.buf);
}

render () {
  console.log("render:"+this.state.buf);
    return(<div>
               Hello World
    </div>
    )
}

といったコードを作成し実行すると

ClickTest:hello
render:hogehoge

が得られます。
このようにrenderはsetStateによる値セット処理実行後に読み出されるので、
先ほどのようなコールバック関数などを用いる必要がないです。

なお、renderとsetStateの関係についてはこちらのブログにまとまっておりました。
参考にしてください。
[React]setState実行時のrenderメソッドの動きを検証する - Qiita

■最後に

今回はsetStateの非同期処理とその対処方法についてまとめておきました。
さて、、、
引き続きチャットボットの作成を進めてまります。
作成完了したらご紹介したいと思いますので、よろしくお願いします。


■参考
https://www.aizulab.com/blog/react-usestate-callback/
https://qiita.com/xx2xyyy/items/76ab9f7d5ff515468a7d
https://qiita.com/ozaki25/items/b7cc9434e83b5e0fe59b