web-dev-qa-db-ja.com

setStateがSyncではなくreactjs Asyncに含まれるのはなぜですか?

任意のコンポーネントのthis.setState()関数が非同期であるか、または呼び出された関数の完了後に呼び出されることを確認しました。

今、私はこのブログを検索して見つけました( http://www.bennadel.com/blog/2893-setstate-state-mutation-operation-may-be-synchronous-in-reactjs.htm

ここで彼はsetStateがどのように状態の変化が引き起こされたかに応じてasync(スタックが空のときに呼ばれる)またはsync(呼ばれるとすぐに呼ばれる)であることを発見しました。

今、これら二つのことは消化するのが難しいです

  1. ブログではsetState関数は関数updateStateの中で呼び出されていますが、updateState関数をトリガーしたものは呼び出された関数が知っているものではありません。
  2. なぜJSはシングルスレッド言語であり、このsetStateはWebAPIまたはサーバー呼び出しではないため、setStateを非同期にするのですか。したがって、JSのスレッド上でのみ実行する必要があります。 Re-Renderingがすべてのイベントリスナや機能を停止しないように、または他の設計上の問題があるように、これを行っていますか。
98
Anup

状態値が更新された後に関数を呼び出すことができます。

this.setState({foo: 'bar'}, () => { 
    // Do something here. 
});

また、一度に更新する状態がたくさんある場合は、それらすべてを同じsetState内にグループ化します。

の代わりに:

this.setState({foo: "one"}, () => {
    this.setState({bar: "two"});
});

これをしてください。

this.setState({
    foo: "one",
    bar: "two"
});
130
JoeTidee

1.)setStateアクションは非同期であり、パフォーマンス向上のためにバッチ処理されます。これはsetStateのドキュメントで説明されています。

setState()はthis.stateをすぐには変更しませんが、保留状態遷移を作成します。このメソッドを呼び出した後にthis.stateにアクセスすると、既存の値が返される可能性があります。 setStateへの呼び出しの同期操作についての保証はなく、呼び出しはパフォーマンスの向上のためにバッチ処理される可能性があります。


2。)なぜJSはシングルスレッド言語であり、このsetStateはWebAPIまたはサーバー呼び出しではないので、setStateを非同期にするのでしょうか。

これは、setStateが状態を変更し、再レンダリングを引き起こすためです。これは高価な操作であり、同期させるとブラウザが応答しなくなる可能性があります。
したがって、setStateの呼び出しは非同期であり、UIの操作性とパフォーマンスを向上させるためにまとめられています。

68
Sachin

私はこの質問が古いことを知っていますが、私を含め、長い間、多くのreactユーザーに多大な混乱を引き起こしてきました。最近、(反応チームの)Dan Abramovが、setStateの性質がなぜ非同期であるかについての素晴らしい説明を書いたばかりです。

https://github.com/facebook/react/issues/11527#issuecomment-36019971

setStateは非同期であることを意図しており、Dan Abramovによるリンクされた説明にはそのための本当に良い理由がいくつかあります。これは常に非同期になるという意味ではありません - それは主にあなたが依存できないということを意味します同期している同期。 ReactJSは、状態を変更しているシナリオの多くの変数を考慮して、stateが実際にいつ更新され、コンポーネントが再描画されるかを決定します。
これを示す簡単な例は、ユーザーアクションに対する反応としてsetStateを呼び出すと、おそらくstateが直ちに更新されることです(ただし、これも当てにすることはできません)。ユーザーが遅延を感じることはありませんが、ユーザーがトリガーしないajax呼び出し応答またはその他のイベントに応答してsetStateを呼び出した場合、状態がわずかに遅れて更新される可能性があります。本当にこの遅れを感じます、そしてそれは複数の状態更新をまとめてまとめてDOMを再描画するのをより少ない回数待つことによってパフォーマンスを改善します。

13
gillyb

ここによい記事 https://github.com/vasanthk/react-bits/blob/master/patterns/27.passing-function-to-setState.md

// assuming this.state.count === 0
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
// this.state.count === 1, not 3

Solution
this.setState((prevState, props) => ({
  count: prevState.count + props.increment
}));

またはコールバックthis.setState ({.....},callback)を渡す

https://medium.com/javascript-scene/setstate-gate-abc10a9b2d82https://medium.freecodecamp.org/functional-setstate-is-the-future-of-)反応-374f30401b6b

6
zloctb

あるコンポーネントのカウンタをインクリメントすることを想像してみてください。

  class SomeComponent extends Component{

    state = {
      updatedByDiv: '',
      updatedByBtn: '',
      counter: 0
    }

    divCountHandler = () => {
      this.setState({
        updatedByDiv: 'Div',
        counter: this.state.counter + 1
      });
      console.log('divCountHandler executed');
    }

    btnCountHandler = () => {
      this.setState({
        updatedByBtn: 'Button',
        counter: this.state.counter + 1
      });
      console.log('btnCountHandler executed');
    }
    ...
    ...
    render(){
      return (
        ...
        // a parent div
        <div onClick={this.divCountHandler}>
          // a child button
          <button onClick={this.btnCountHandler}>Increment Count</button>
        </div>
        ...
      )
    }
  }

親コンポーネントと子コンポーネントの両方にアタッチされたカウントハンドラがあります。これは意図的に行われているので、同じクリックイベントのバブリングコンテキスト内で2つの異なるハンドラ内からsetState()を2回実行できます。

想像しているように、バブリング段階ではイベントがターゲットから一番外側のコンテナに向かってバブルするので、ボタンをクリックするとこれらのハンドラが両方ともトリガされます。

したがって、btnCountHandler()が最初に実行され、カウントを1に増分することが予想され、次にdivCountHandler()が実行されて、カウントが2に増分することが予想されます。

ただし、React Developerツールで調べることができるので、カウントは1にしかなりません。

これは反応することを証明する

  • すべてのsetState呼び出しをキューに入れる

  • コンテキスト内の最後のメソッド(この場合はdivCountHandler)を実行した後、このキューに戻ります。

  • 同じコンテキスト内の複数のsetState呼び出し内で発生したすべてのオブジェクトの変更(単一のイベントフェーズ内のすべてのメソッド呼び出しは同じコンテキストなど)を単一のオブジェクト変更構文にマージします(これがステートプロパティを個別に更新できる理由です)そもそもsetState()で

  • 複数のsetState()呼び出しによる再レンダリングを防ぐために1つの単一のsetState()に渡します(これはバッチ処理の非常に原始的な説明です)。

Reactによって実行される結果コード

this.setState({
  updatedByDiv: 'Div',
  updatedByBtn: 'Button',
  counter: this.state.counter + 1
})

SetStateメソッドの引数としてオブジェクトを渡すのではなく、この動作を止めるためにコールバックが渡されます。

    divCountHandler = () => {
          this.setState((prevState, props) => {
            return {
              updatedByDiv: 'Div',
              counter: prevState.counter + 1
            };
          });
          console.log('divCountHandler executed');
        }

    btnCountHandler = () => {
          this.setState((prevState, props) => {
            return {
              updatedByBtn: 'Button',
              counter: prevState.counter + 1
            };
          });
      console.log('btnCountHandler executed');
    }

最後のメソッドが実行を終了した後、reactがsetStateキューの処理に戻ったとき、キューに入れられた各setStateのコールバックを呼び出して、前のコンポーネント状態を渡します。

このように反応することで、キュー内の最後のコールバックが、以前のすべての対応物が手をかけた状態を確実に更新します。

1
supi

次のラップを使用して同期呼び出しを行うにすることができます。

this.setState((state =>{
  return{
    something
  }
})
0
Ярослав

はい、setState()は非同期です。

リンクから: https://reactjs.org/docs/react-component.html#setstate

  • Reactは、状態の変更がすぐに適用されることを保証しません。
  • setState()は、必ずしもすぐにコンポーネントを更新するとは限りません。
  • SetState()は、コンポーネントを更新するための即時コマンドではなく、リクエストと考えてください。

彼らが考えるから
リンクから: https://github.com/facebook/react/issues/11527#issuecomment-36019971

...多くの場合、setState()の同期的な再レンダリングは非効率的であることに同意します

非同期のsetState()を使用すると、開始したばかりでなく不幸にも経験を積む人にとって非常に困難です。
-予期しないレンダリングの問題:レンダリングの遅延またはレンダリングなし(プログラムロジックに基づく)
-パラメータの受け渡しは大したことです
その他の問題。

以下の例が役立ちました:

// call doMyTask1 - here we set state
// then after state is updated...
//     call to doMyTask2 to proceed further in program

constructor(props) {
    // ..

    // This binding is necessary to make `this` work in the callback
    this.doMyTask1 = this.doMyTask1.bind(this);
    this.doMyTask2 = this.doMyTask2.bind(this);
}

function doMyTask1(myparam1) {
    // ..

    this.setState(
        {
            mystate1: 'myvalue1',
            mystate2: 'myvalue2'
            // ...
        },    
        () => {
            this.doMyTask2(myparam1); 
        }
    );
}

function doMyTask2(myparam2) {
    // ..
}

お役に立てば幸いです。