web-dev-qa-db-ja.com

React setState / getStateおよび非同期

React?に非同期getState関数がない理由

ドキュメントから、setStateは非同期であることがわかります。ただし、これはthis.stateを安全に使用できないことを意味し、実行順序を尊重するために非同期getStateも必要です。

私が理解していることから、this.stateを使用して、次のようなgetState関数を使用しないでください

  getState(callback) {
    this.setState((prevState) => {
      callback(prevState) ;
    });
  }
  ...
  this.getState((curState) => {
    // we now can use the current state safely
  }

私の考え方でここに欠けているものはありますか?なぜそのような関数がReact?

-編集-

私の友人が私に言ったように、それは明確ではなく、私は確信していないが最初の答えなので、いくつかのコードを分析しましょう:

simpleFunc() {
    setState({ "counter" : 1 });
    setState({ "counter" : 2 });
    this.state.counter // => no garanty about the value
    getState((curState) => {  // ensure curState.counter is 2 });
}

この簡単な例は、setStateが非同期であるため、すべての状況でthis.stateを直接使用できないことを示しています

GetStateを使用できるカウンターの例を次に示します。 http://codepen.io/Epithor/pen/ZLavWR?editors=0010#

簡単な答え:悪い状態です。

回避策は簡単ですが、一部の関数を因数分解し、コンテキストを気にせずに使用できるという事実は興味深いようです。

したがって、特定の順序で多数のイベントが発生すると、一部のイベントは状態を変更し、一部のイベントは状態を読み取ります:イベントがthis.stateすべての変更が非同期であるため、良好な状態を読み取るには?

実際にはすべては時間についてです:

T     : event 1, change state
T+1ms : event 2, change state
T+2ms : event 3, read state
T+3ms : event 4, change state

イベント1または2のsetStateが正確にいつ発生するかを予測できないため、イベント3がイベント2で設定された状態を実際に読み取ることをどのように保証できますか?

短い答え:イベントはJSスタックでキューに入れられますが、状態変更は内部でキューに入れられますReactキュー。内部Reactキューはハンドを与える前に完全にアンスタックされます。

7
user2668735

間違いなく_this.state_を直接一般的に使用できます。状態を直接mutateしてはいけません(_this.state.foo = 0_)、代わりにsetStateを使用して状態を変更する必要があります。

通常、setStateは次のようになります。

_this.setState({
    foo: 0
})
_

その後、render()関数などで_this.state.foo_を安全に使用できます。

ただし、setStateの非同期的な性質により、setStateが呼び出された後に_this.state_にすぐにアクセスできるという保証はありません。

_myFunc(baz) {
    this.setState({
        foo: baz + 1
    })
    console.log(this.state.foo) // not guaranteed
}
_

やったほうがいい

_myFunc(baz) {
    const bazOne = baz + 1
    this.setState({
        foo: bazOne
    })
    console.log(bazOne)
}
_

または、setState関数の2番目のパラメーターを使用します。これは、setState操作が終了したときに実行されるコールバックとして使用されます。そのコールバックでは、更新された状態、つまり_this.state_にアクセスできます。

this.setState({ foo }, () => { console.log(this.state.foo) });

参照: https://facebook.github.io/react/docs/react-component.html#setstate

14
inostia

それは実際にはバグ/問題ではなく、アーキテクチャの決定です:stateは単純なプロパティ/変数/ストレージとして使用されることを意図していません。 、呼び出しごとに更新する必要はありません。内部キューを使用するため、レンダリングの前に何度も状態をスワップすると、実際には最終値で1回だけ更新され、renderメソッドが呼び出されるまでに適切な値が含まれます。

実行中または同じフェーズで実行されるメソッド間(たとえば[componentWillReceivePropsshouldComponentUpdate)で情報を保存/取得する必要がある場合は、this.anyPropertyを安全に使用できます。常に:

componentWillReceiveProps() {
  this.value = 'guaranteed';
  return true;
}
shouldComponentUpdate() {
  if (this.value === 'guaranteed') {
    console.log('will always return true');
  }
}
componentDidUpdate() {
  this.value = ''; //cleanup
}

上記の例では、「setState」を使用した場合、「shouldComponentUpdate」で値が常に更新されるという保証はありませんが、意図した目的で使用するかどうかは重要ではありません。状態の変更はrender時間までにフラッシュされることが保証されているため、オブジェクトのトランザクション/内部データではなく、レンダリングフェーズで使用される情報のみが含まれている必要があります。通常どおり、オブジェクトのプロパティを自由に使用できます。

2
diego nunes

setStateは非同期であるため、変更したプロパティにすぐにアクセスすることはできませんが、状態が変更された後にアクションを実行したい場合があります。

...

this.state = {
  x = 1
}

...

this.setState({
  x = 2
}, () => {
  console.log(this.state.x) // outputs 2
});

setState関数はキューに入れられたティックで呼び出されるので、x個のsetStateをキューに入れることができ、それらはすべて次のティックで実行されます。

2
ospfranco