React setStateコールバックを使用する場合


191

反応コンポーネントの状態が変化すると、renderメソッドが呼び出されます。したがって、状態が変化した場合、レンダリングメソッドの本体でアクションを実行できます。次に、setStateコールバックの特定の使用例はありますか?


4
現在、何を求めているのか不明です。いくつかのコードを含めることはできますか?
Davin Tryon 2017

2
setStateコールバックは、状態がDEFINITELYに変更された後に実行するすべてのことを行うためのものです。setStateは非同期なので、fxを呼び出して新しい状態がロードされていることを確認したい場合は、それがコールバックの目的です
Jayce444

3
setStateコールバックの使用例は非常に明確です。SPECIFIC状態が更新された後に関数を実行する場合に使用します。render()代わりにこの関数を配置 すると、すべての状態が更新されるたびに実行されますが、これはおそらく望んでいないことです。これにより、コードが読みにくくなり、論理的でなくなります。
M3RS 2018

回答:


222

はい以来、そこにあるsetStateで働くasynchronous方法。つまりsetStatethis.state変数を呼び出した後、すぐには変更されません。したがって、状態変数に状態を設定した直後にアクションを実行し、結果を返す場合は、コールバックが役立ちます

以下の例を検討してください

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value });
  this.validateTitle();
},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

上記のコードは、title検証が実行される前に変数が変化していない可能性があるため、期待どおりに機能しない可能性があります。これで、render()関数自体で検証を実行できるのではないかと思うかもしれませんが、コードをより整理して理解できるようにするため、changeTitle関数自体でこれを処理できれば、より適切でクリーンな方法になります。

この場合、コールバックが役立ちます

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value }, function() {
    this.validateTitle();
  });

},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

もう1つの例はdispatch、状態が変化したときにアクションを実行する場合です。あなたは、コールバックやないでそれを行うことになるでしょうrender()、それは毎回再描画が発生呼び出され、コールバックを必要とする場所、したがって多くのそのようなシナリオが考えられると。

別のケースは API Call

特定の状態の変化に基づいてAPI呼び出しを行う必要がある場合、状況が発生する可能性があります。renderメソッドでそれを行うと、レンダリングがonState変更されるたびに、または一部のプロップがChild Component変更に渡されるために呼び出されます。

この場合、setState callbackを使用して、更新された状態値をAPI呼び出しに渡します。

....
changeTitle: function (event) {
  this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
  // Call API with the updated value
}
....

3
私はそれが本質的に非同期であることを理解しています。私の質問は、おそらくsetStateコールバックのみを使用できるという特定の何かがあり、それがおそらくレンダリングメソッドの本体でサポートされない可能性があるということです(コードの読みやすさを向上させるとしましょう。)
Sahil Jain

@SahilJain Validationは正しい例です。render()関数で変更を行うたびに呼び出されるので、render()関数でそれを処理する必要はありません。関数自体
Shubham Khatri 2017

Reactはレンダリング中に状態を変更することを禁止します。したがって、検証をコールバックに入れる権利があります。
webdeb 2017

if (this.title.length === 0) {である必要がthis.state.title.lengthありますか?
ドミトリーミンコフスキー2017年

4
最初のユースケースはおそらく良い考えではありません。setStateコールバックは再レンダリング後にトリガーされるため、正当な理由なく二重レンダリングを引き起こしています。これがまさに関数の引数(アップデーター)の目的です。実行するだけでsetState(state => state.title.length ? { titleError: "Title can't be blank" } : null)変更がスタックします。二重レンダリングは必要ありません。
R Esmond 2018

46
this.setState({
    name:'value' 
},() => {
    console.log(this.state.name);
});

14
このコードスニペットをありがとうございます。このコードスニペットは、限られた、即時の助けを提供する可能性があります。適切な説明が大幅に長期的な価値を向上させるだろう示すことによって、なぜこれが問題に良い解決策であり、他の、同様の質問を将来の読者にそれがより便利になるだろう。答えを編集して、仮定を含めて説明を追加してください。
Machavity、2018年

1
状態が変化した後に関数を呼び出す場合は、メソッドを使用できます。
アラズババエフ2018年

名前、名などの複数の状態のプロパティを設定する場合はどうなりますか?
Sumanth Varada

44

1.頭に浮かぶユースケースはapi呼び出しであり、each状態変更のために実行されるため、レンダーには入れるべきではありません。また、API呼び出しは、すべてのレンダリングではなく、特別な状態変更時にのみ実行する必要があります。

changeSearchParams = (params) => {
  this.setState({ params }, this.performSearch)
} 

performSearch = () => {
  API.search(this.state.params, (result) => {
    this.setState({ result })
  });
}

したがって、状態が変化した場合、レンダリングメソッドの本体でアクションを実行できます。

-renderメソッドは純粋でなければならないため、非常に悪い習慣です。つまり、アクション、状態変更、API呼び出しは実行されず、ビューを合成して返すだけです。アクションは、一部のイベントに対してのみ実行する必要があります。レンダリングはイベントではなく、componentDidMountたとえばです。


25

setState呼び出しを検討する

this.setState({ counter: this.state.counter + 1 })

考え

setStateは非同期関数で呼び出すことができます

したがって、あなたは信頼することができませんthis。上記の呼び出しが非同期関数内で行われた場合、thisその時点でのコンポーネントの状態を参照しますが、setState呼び出しまたは非同期タスクの開始時の状態内のプロパティを参照することを期待していました。そして、タスクは非同期呼び出しだったので、そのプロパティはしばらくすると変更された可能性があります。したがって、thisキーワードを使用して状態のプロパティを参照することは信頼できません。したがって、引数がpreviousStateとpropsであるコールバック関数を使用します。つまり、非同期タスクが実行され、setState呼び出しを使用して状態を更新するときでした。prevStateは、setStateのときに状態を参照します。まだ始まっていません。nextStateが破損しないという信頼性を保証します。

間違ったコード:データの破損につながる

this.setState(
   {counter:this.state.counter+1}
 );

コールバック関数を持つsetStateを含む正しいコード:

 this.setState(
       (prevState,props)=>{
           return {counter:prevState.counter+1};
        }
    );

したがって、現在の状態をプロパティが持つ値に基づいて次の状態に更新する必要があり、これがすべて非同期で行われているときはいつでも、コールバック関数としてsetStateを使用することをお勧めします。

私は コードペンでそれを説明しようとしましたここコードペン

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.