2

私は現在、ReactJS に一般的に関連付けられているフラックス パターンを使用して、プロトタイプ アプリケーションに取り組んでいます。

Facebookフラックス/チャットの例では、 ThreadStoreUnreadThreadStoreの 2 つのストアがあります。後者は、前者のコンテンツを同期的に読み取るgetAllメソッドを提供します。

派生ストアでの操作はコストがかかりすぎて同期的に実行できず、理想的には非同期プロセス (Web ワーカー、サーバー トリップ) に委任されるという問題が発生しました。これを解決するにはどうすればよいか考えています。

私の同僚は、ゲッターからプロミスを返すことを提案しています。

# MyView

componentDidMount: function () {
    defaultState = { results: [] };
    this.setState(defaultState);
    DerivedStore.doExpensiveThing()
        .then(this.setState);
}

私はこれに完全に満足していません。ビューはストアではなく変更の主な受信者であるため、パターンとの決別のように感じます。これは、私たちが検討してきた別の手段です。この方法では、ビューのマウント イベントが、派生データを更新する要求をディスパッチします (必要な場合)。

 # DerivedStore
 # =========================================================
 state: {
     derivedResults: []
     status: empty <fresh|pending|empty>
 },
 handleViewAction: function (payload) {
    if (payload.type === "refreshDerivedData") {
        this.state.status = "pending"; # assume an async action has started
    }
    if (payload.type === "derivedDataIsRefreshed") {
        this.state.status = "fresh"; # the async action has completed
    }
    this.state.derivedResults = payload.results || []
    this.notify();
 }

 # MyAction
 # =========================================================
 MyAction = function (dispatcher) {
    dispatcher.register(function (payload) {
        switch (payload) {
            case "refreshDerivedData": 
               doExpensiveCalculation()
                   .then(function(res) {
                        dispatcher.dispatch({
                            type: "derivedDataIsRefreshed",
                            results: res
                        })
                    })
               );
        }
    });
 };

 # MyView
 # =========================================================
 MyView = React.createClass({
     componentDidMount: function () {
         if (DerivedStore.getState().status === "empty") {
             Dispatcher.dispatch("refreshDerivedData");
         }
     },
     getVisibility: function () {
         return DerivedStore.getState().status === "pending" ? "is-visible" : ""
     },
     render: function () {
         var state = DerivedStore.getState()
             , cx = React.addons.classSet
             , classes = cx({
                "spinner-is-visible": state.status === "pending"
             });

         return <div {classes}>
                   <Spinner /> # only visible if "spinner-is-visible
                   <Results results={state.derivedResults}/> # only visible if not...
                </div>;
     }

 });


 # MyService
 # =========================================================

 # ensure derived data is invalidated by updates in it's source?
 OriginalStore.addListener(function () {
     setTimeout(function () {
        dispatcher.dispatch({
            type: "refreshDerivedData"
        })
     }, 0); 

 });

このアプローチで私が気に入っているのは、ビューが DerivedStore をビュー モデルとして扱い、この類のビューが主にビュー モデルの鮮度に関心があることです。しかし、私が懸念しているのは、ストアが同期しなくなる可能性です。

私の質問は次のとおりです。

  • 約束のアプローチは受け入れられますか?
  • 2番目のアプローチはより良い/より悪いですか?もしそうなら、なぜですか?
  • この問題に対する既存の「標準的な」アプローチはありますか?

PS: このコードに基本的なリンティング エラーがある場合は申し訳ありません。私は過去 3 か月間 Coffeescript で作業しており、リンティング機能が破壊されました...

4

4 に答える 4

2

すべての非同期アクションは、アクションの作成によって発生する必要があります。非同期アクションの完了は、別のアクションの作成によって通知される必要があります。ストアはこれらのアクションをリッスンし、変更イベントを発行できます。

コンポーネントでは、DerivedStore の変更をリッスンします。アクションは、コンポーネントや別のストアなど、どこからでも作成できます。データが (最終的に) 派生され、ストアが更新され、変更イベントが発行され、コンポーネントがイベント ペイロードを状態に適用します。

全体として、コンポーネントは、舞台裏で起こっていることが同期か非同期かを実際には認識していません。コンポーネントを壊すリスクなしに、これらのパフォーマンスの変更を舞台裏で行うことができるため、これは素晴らしいことです。

純粋なストアには通常、ストアの状態を取得するパブリック関数が 1 つしかありません。コンポーネントでは、これを getInitialState でのみ呼び出す必要があります。さらに良いのは、これを実行して変更リスナーを追加する mixin を用意することです。

于 2014-12-04T18:52:48.697 に答える
1

可能な限り Flux の方法で非同期プロセスを作成する場合は、XHR リクエストと同じようにアプローチします。Action Creator または Store のいずれか (アプリにとって最も意味のある方) で非同期プロセスを開始します。次に、新しいアクション クリエーターを呼び出して、非同期プロセスが完了したときに新しいアクションをディスパッチします。このようにして、複数のストアが完了した高価な非同期プロセスに応答でき、データ フローは引き続きアクションから発生します。

于 2014-12-04T18:35:53.657 に答える