web-dev-qa-db-ja.com

ディスパッチの途中でディスパッチを回避する方法

Flux architected Reactアプリケーション内で、ストアからデータを取得しており、その情報が存在しない場合にその情報を要求するアクションを作成したいのですが、ディスパッチャがエラーになりますすでに発送しています。

私の望ましいコードは次のようなものです:

_getAll: function(options) {
  options = options || {};
  var key = JSON.stringify(options);
  var ratings = _data.ratings[key];

  if (!ratings) {
    RatingActions.fetchAll(options);
  }

  return ratings || [];
}
_

ただし、ディスパッチャがすでにアクションをディスパッチしているときに、メッセージInvariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.で断続的に失敗します。アプリケーションの状態(日付範囲など)の変化に応じてリクエストを行うことがよくあります。 AppStoreからの変更イベントに応答してリクエストを行うコンポーネントには、次のものがあります。

_getStateFromStores: function() {
  var dateOptions = {
    startDate: AppStore.getStartISOString(),
    endDate: AppStore.getEndISOString()
  };

  return {
    ratings: RatingStore.getAll(dateOptions),
  };
},
_

イベントチェーンはFluxのアンチパターンであることは承知していますが、データがまだ存在しない場合にデータを取得するのにどのアーキテクチャが優れているかはわかりません。現在、私はこの恐ろしいハックを使用しています:

_getAll: function(options) {
  options = options || {};
  var key = JSON.stringify(options);
  var ratings = _data.ratings[key];

  if (!ratings) {
    setTimeout(function() {
      if (!RatingActions.dispatcher.isDispatching()) {
        RatingActions.fetchAll(options);
      }
    }, 0);
  }

  return ratings || [];
},
_

イベントチェーンやディスパッチャエラーを回避する、より優れたアーキテクチャは何でしょうか?これは本当にイベントチェーンですか?アプリケーションが設定したパラメーターに基づいてデータを変更したいだけです。

ありがとう!

19

SetTimeoutの代わりにFlux waitFor() functionを使用できます

たとえば、同じディスパッチャに2つのストアを登録し、1つのストアを待機して、他のストアが最初にアクションを処理し、次に待機しているストアが変更イベントを更新してディスパッチできるようにします。 Flux docsを参照してください

13
andykenward

私の特定のエラーは、ストアがリスナーを循環している間に、アクションのディスパッチ中に変更イベントを発行したために発生していました。これは、ストア内のデータ変更によりアクションをトリガーしたリスナー(コンポーネント)がディスパッチを中断することを意味していました。ディスパッチが完了した後にchangeイベントを発行することで修正しました。

したがって、この:

this.emit(CHANGE_EVENT);

なりました

var self = this;

setTimeout(function() { // Run after dispatcher has finished
  self.emit(CHANGE_EVENT);
}, 0);

まだ少しハッキーです(おそらく書き換えられるので、setTimeoutは不要です)。この実装の詳細ではなく、アーキテクチャの問題に対処するソリューションを受け入れます。

6

前のディスパッチの途中でディスパッチを取得する理由は、ストアが別のアクションのハンドラーでアクションをディスパッチする(アクションクリエーターを呼び出す)同期的にであるためです。ディスパッチャは、登録されたすべてのコールバックが実行されるまで技術的にディスパッチします。したがって、登録されたコールバックのいずれかから新しいアクションをディスパッチすると、そのエラーが発生します。

ただし、非同期作業を行う場合、たとえばajaxリクエストを作成しても、アクションajaxコールバック内、または一般的に非同期コールバックをディスパッチできます。これは機能します。非同期関数が呼び出されるとすぐに、定義ごとにすぐに関数の実行が継続され、コールバックがイベントキューに配置されるためです。

アミダとその回答のコメントで指摘されているように、アクションに応じてストアからajaxリクエストを行うか、ストアでそれを行うかは選択の問題です。重要な点は、ストアが状態を変更するだけである必要があることですアクションへの応答でであり、ajax/asyncコールバックではありません。

あなたの特定のケースでは、ストアからajax呼び出しを行うことを好む場合、これはあなたのストアの登録されたコールバックのためのこのような何かによって例示されるでしょう:

onGetAll: function(options) {
    // ...do some work

    request(ajaxOptions) // example for some promise-based ajax lib
        .then(function(data) {
             getAllSuccessAction(data); // run after dispatch
        })
        .error(function(data) {
             getAllFailedAction(data); // run after dispatch
        });

     // this will be immediately run during getAllAction dispatch
     return this.state[options];
},
onGetAllSuccess: function(data) {
    // update state or something and then trigger change event, or whatever
},    
onGetAllFailed: function(data) {
    // handle failure somehow
}

または、アクション作成者にajax呼び出しを入れて、そこから「成功/失敗」アクションをディスパッチするだけです。

5

ディスパッチャで「遅延」オプションを使用できます。あなたの場合、それは次のようになります:

RatingActions.fetchAll.defer(options);
1
abhisekpaul

私の場合、アクション/アクション作成者からデータを取得します。ストアは、アクションのペイロードを受け取る単なるダンプ場所です。

これは、アクションで「フェッチオール」し、結果をストアに渡すことを意味します。ストアはそれを使って何でもし、変更イベントを発行します。

私のような店を使うことを考えている人もいれば、あなたのように考えている人もいます。 Facebookの一部の人々は「私の」アプローチを使用しています。

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/utils/ChatWebAPIUtils.js#L51

おそらくこのように店舗を扱う発送の問題を回避できると思いますが、私は間違っているかもしれません。

興味深い議論はこれです: https://groups.google.com/forum/#!topic/reactjs/jBPHH4Q-8Sc

jing Chen(Facebookエンジニア)は、店舗の使い方について彼女が考えていることを説明しています。

0
Kev