this.setStateをReactコンポーネントで複数回使用するとどうなりますか?


100

this.setStateを複数回(説明のために2回)使用するとどうなるかを確認したいと思います。コンポーネントは2回レンダリングされると思いましたが、どうやら1回しかレンダリングされないようです。私が持っていたもう1つの期待は、おそらくsetStateの2番目の呼び出しが最初の呼び出しを実行することでしたが、あなたはそれを推測しました-うまくいきました。

JSfiddleへのリンク

var Hello = React.createClass({
  render: function() {
    return (
      <div>
        <div>Hello {this.props.name}</div>
        <CheckBox />
      </div>
    );
  }
});

var CheckBox = React.createClass({
  getInitialState: function() {
    return {
      alex: 0
    };
  },

  handleChange: function(event) {
    this.setState({
      value: event.target.value
    });
    this.setState({
      alex: 5
    });
  },

  render: function() {
    alert('render');
    return (
      <div>
        <label htmlFor="alex">Alex</label>
        <input type="checkbox" onChange={this.handleChange} name="alex" />
        <div>{this.state.alex}</div>
      </div>
    );
  }
});

ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('container')
);

ご覧のとおり、すべてのレンダリングで「レンダリング」という警告がポップアップ表示されます。

それが正しく機能した理由について説明がありますか?


2
Reactはかなり賢く、レンダリングに必要な状態が変更された場合にのみ再レンダリングされます。あなたが使用しているrenderメソッドでthis.state.alex-依存する要素を追加するとどうなりますthis.state.valueか?
Martin Wedvich 2015年

1
@MartinWedvich私がそれに依存している場合、壊れます。そのためには、「getInitialState」メソッドを使用します-アプリが壊れないようにデフォルト値を設定します。
alexunder 2015年

回答:


115

Reactは、イベントハンドラーとライフサイクルメソッドで発生する状態更新をバッチ処理します。したがって、状態を複数回更新した場合、<div onClick />ハンドラーで、Reactはイベント処理が完了するのを待ってから再レンダリングします。

明確に言うと、これはReact制御の合成イベントハンドラーとライフサイクルメソッドでのみ機能します。setTimeoutたとえば、AJAXやイベントハンドラーでは状態の更新はバッチ処理されません。


1
ありがとう、それは理にかなっています、それがどのように舞台裏で行われるかについての考え?
alexunder 2015年

13
Reactは合成イベントハンドラー(など<div onClick />)とコンポーネントのライフサイクルメソッドを完全に制御するsetStateため、バッチ状態更新の呼び出しの間、の動作を安全に変更し、フラッシュを待機できることがわかります。setTimeout対照的に、AJAXまたはハンドラーでは、Reactはハンドラーの実行がいつ終了したかを知る方法がありません。技術的には、Reactはどちらの場合も状態の更新をキューに入れますが、Reactが制御するハンドラーのすぐ外側でフラッシュします。
Chris Gaudreau、2015年

1
@neurosnap私はドキュメントがこれについて詳細に入るとは思わない。これは、State and LifecycleセクションsetState docsで抽象的に説明されています。現在唯一の公式のバッチ戦略であるReactDefaultBatchingStrategyのコードを参照してください。
Chris Gaudreau 2017

2
@BenjaminToueg Reactイベントハンドラの外でReactDOM.unstable_batchedUpdates(function)バッチ処理を使用できると思いsetStateます。名前が示すように、保証は無効になります。
Chris Gaudreau 2017


32

setState()メソッドは、コンポーネントの状態をすぐに更新するのではなく、後で処理するために更新をキューに入れるだけです。Reactは、レンダリングをより効率的にするために、複数の更新リクエストをバッチ処理する場合があります。このため、コンポーネントの以前の状態に基づいて状態を更新する場合は、特別な注意が必要です。

たとえば、次のコードは、4回呼び出された場合でも状態値属性を1だけインクリメントします。

 class Counter extends React.Component{
   constructor(props){
     super(props)
    //initial state set up
     this.state = {value:0}
   }
   componentDidMount(){
    //updating state
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
   }
   render(){
    return <div>Message:{this.state.value}</div>
   }
}

更新された状態を使用するには、コールバック引数ですべてのロジックを実行します。

//this.state.count is originally 0
this.setState({count:42}, () => {
  console.log(this.state.count)
//outputs 42
})

setState(updater、[callback])メソッドは、前の状態とプロパティに基づいて状態を更新する最初の引数としてupdater関数を取り込むことができます。アップデーター関数の戻り値は、以前のコンポーネントの状態と浅くマージされます。このメソッドは状態を非同期に更新するため、状態の更新が完全に完了すると呼び出されるオプションコールバックがあります。

例:

this.setState((prevState, props) => { 
return {attribute:"value"}
})

以前の状態に基づいて状態を更新する方法の例を次に示します。

    class Counter extends React.Component{
      constructor(props) {
        super(props)
    //initial state set up
        this.state = {message:"initial message"}
    }
      componentDidMount() {
    //updating state
        this.setState((prevState, props) => {
          return {message: prevState.message + '!'}
        })
     }
     render(){
       return <div>Message:{this.state.message}</div>
     }
  }

ああ、私はについて知りませんでしたsetState(updater,[callback])、それはそれほど冗長Object.assignではない感謝のようです!
AJ Venturella、

1
@Biboswan、こんにちは、私はReactが初めてで、CompountDidMountメソッド内の4つのsetStateがすべてマージされ、最後のsetStateのみが実行され、他の3つは無視されるというのは本当ですか?
ディケンズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.