ジャンボモナカ

34歳のハゲデブがHTML5ハイブリッドアプリ開発プラットフォームmonacaを始めました。

ReactのsetStateでstateが即時反映されない件

ReactでsetStateを呼び出した直後にその変数を参照しにいこうとすると更新が反映されていないケースがある。

例えば、componentDidMountメソッドでsetStateを呼び出して、stateの更新依頼をかけた後、すぐにcomponentDidMountメソッド内でそのstateを参照する場合、値が反映されていないケース。

class Hoge extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      foo:1
    };
  }

  componentDidMount(){
    this.setState({
      foo:2
    })
    // 下は1となる(本来は2になってほしい)
    console.log(this.state.foo)
  }
  render(){
    return <span>{this.state.foo}</span>
  }
}

ReactDOM.render(
  <Hoge />,
  document.getElementById('bar')
);

renderメソッドで使われるstateの値に関しては更新が完了した後に呼び出されるので正常に動作する。

この件に関しては、Facebookも把握しており、In depth: Why isn’t this.state updated immediately?というリンクがあった。

github.com

では、stateが更新されたタイミングで特定の処理を実行したい場合はどうすればいいのだろうか?

これも公式サイトに書いてあったのだが、componentDidUpdateメソッドを呼び出すか、setStateメソッドでコールバックを呼び出すことで対応できるようだ。 (ってかコールバックぐらいmain conceptsに書いておけよって言いたくなるのは気のせい?)

まずは、componentDidUpdateメソッドを使ったパターン

class Hoge extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      foo:1
    };
  }

  componentDidMount(){
    this.setState({
      foo:2
    })
    
  }

  componentDidUpdate(prevProps, prevState, snapshot){
    // 下は2になる(正常終了)
    console.log(this.state.foo)
  }

  render(){
    return <span>{this.state.foo}</span>
  }
}

ReactDOM.render(
  <Hoge />,
  document.getElementById('bar')
);

次にsetStateのコールバックを使ったパターン

class Hoge extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      foo:1
    };
  }

  componentDidMount(){
    this.setState({
      foo:2
    },()=>{
      // 下は2になる(正常終了)
      console.log(this.state.foo)
    })
    
  }

  render(){
    return <span>{this.state.foo}</span>
  }
}

ReactDOM.render(
  <Hoge />,
  document.getElementById('bar')
);

setStateのコールバックもcomponentDidUpdateメソッドを使ったパターンも正常動作した。

しかし、注意点として、複数メンバーで実装を行なっていた場合、使い方をあわせないと、改修を行う際、プログラムの統一性が測れなくなり、混乱をきたす可能性がある。