フラックスストア、またはアクション(またはその両方)は外部サービスに影響を与えるべきですか


122

ストアが独自の状態を維持し、その際にネットワークおよびデータストレージサービスを呼び出す機能を持っている場合、その場合のアクションは単なるメッセージパサーです。

-または-

...ストアは、アクションからの不変データの愚かな受信者である必要があります(アクションは、外部ソース間でデータをフェッチ/送信するものですか?このインスタンスのストアは、ビューモデルとして機能し、それらを集約/フィルタリングできます。アクションによって供給された不変データに基づいて独自の状態ベースを設定する前のデータ。

それはどちらか一方でなければならないようです(両方の組み合わせではありません)。もしそうなら、なぜ一方が他方よりも好ましい/推奨されるのですか?



フラックスパターンのさまざまな実装を評価する方には、Reduxをご覧になることを強くお勧めしますgithub.com/rackt/reduxストアは、現在の状態を取り込み、その状態の新しいバージョンを出力する純粋な関数として実装されています。これらは純粋な関数なので、ネットワークサービスやストレージサービスを呼び出すことができるかどうかという問題はあなたの手から取り除かれます。そうすることはできません。
plaxdan 2015年

回答:


151

フラックスパターンが両方の方法で実装されているのを見てきました。両方を自分で行った後(最初は前のアプローチを使用)、ストアはアクションからのデータの受け手と言えないはずであり、書き込みの非同期処理はアクションクリエイター。(非同期読み取りは異なる方法で処理できます。)私の経験では、これにはいくつかの利点があります。

  1. ストアが完全に同期します。これにより、ストアロジックの追跡が非常に容易になり、テストが非常に簡単になります。特定の状態でストアをインスタンス化し、アクションを送信して、状態が期待どおりに変化したかどうかを確認するだけです。さらに、フラックスのコアコンセプトの1つは、カスケードディスパッチを防ぎ、一度に複数のディスパッチを防ぐことです。ストアが非同期処理を行う場合、これは非常に困難です。

  2. すべてのアクションディスパッチは、アクションの作成者から行われます。ストアで非同期操作を処理し、ストアのアクションハンドラーを同期させておきたい場合(そして、フラックスシングルディスパッチの保証を取得する必要がある場合)、ストアは非同期に応答して追加のSUCCESSおよびFAILアクションを起動する必要があります。処理。代わりに、これらのディスパッチをアクションクリエーターに入れると、アクションクリエーターとストアのジョブを分離するのに役立ちます。さらに、アクションがどこからディスパッチされているかを把握するためにストアロジックを掘り下げる必要はありません。この場合の典型的な非同期アクションは、次のようになります(dispatch使用しているフラックスのフレーバーに基づいて、呼び出しの構文を変更します)。

    someActionCreator: function(userId) {
      // Dispatch an action now so that stores that want
      // to optimistically update their state can do so.
      dispatch("SOME_ACTION", {userId: userId});
    
      // This example uses promises, but you can use Node-style
      // callbacks or whatever you want for error handling.
      SomeDataAccessLayer.doSomething(userId)
      .then(function(newData) {
        // Stores that optimistically updated may not do anything
        // with a "SUCCESS" action, but you might e.g. stop showing
        // a loading indicator, etc.
        dispatch("SOME_ACTION_SUCCESS", {userId: userId, newData: newData});
      }, function(error) {
        // Stores can roll back by watching for the error case.
        dispatch("SOME_ACTION_FAIL", {userId: userId, error: error});
      });
    }

    そうでなければさまざまなアクション間で複製される可能性のあるロジックは、別のモジュールに抽出する必要があります。この例では、そのモジュールはでありSomeDataAccessLayer、実際のAjaxリクエストの実行を処理します。

  3. アクション作成者が少なくて済みます。これは大したことではありませんが、持っておくと便利です。#2で述べたように、ストアに同期アクションディスパッチ処理がある場合は(そうでなければなりません)、非同期操作の結果を処理するために追加のアクションを起動する必要があります。アクションクリエーターでディスパッチを行うと、単一のアクションクリエーターが非同期データアクセス自体の結果を処理することで、3つのアクションタイプすべてをディスパッチできます。


15
成功/エラーコールバックがアクションを作成する必要があるという事実よりも、Web APIコール(アクションクリエーター対ストア)の起源は重要ではないと思います。したがって、データフローは常に次のようになります。アクション->ディスパッチャー->ストア->ビュー。
fisherwebdev 2014

1
実際のリクエストロジックをAPIモジュール内に配置する方が、テストが容易/簡単ですか?したがって、APIモジュールは、ディスパッチしたpromiseを返すだけです。アクション作成者は、最初の「保留中」のアクションを送信した後、解決/失敗に基づいてディスパッチするだけです。残っている問題は、リクエストの状態をストアの状態にマップする必要があるかどうかわからないため、コンポーネントがこれらの「イベント」をどのようにリッスンするかです。
バックデスク2015年

@backdesk上記の例では、まさにそれを行っています。最初の保留中のアクションをディスパッチし("SOME_ACTION")、APIを使用しSomeDataAccessLayer.doSomething(userId)てプロミスを返すリクエストを作成し()、2つの.then関数で追加のアクションをディスパッチします。アプリケーションが状態の状態を知る必要がある場合、要求状態は(多かれ少なかれ)マップして、状態を格納できます。このマップがアプリにどのように対応するか(たとえば、各コメントに個別のエラー状態があるか、Facebookの1つであるか、グローバルエラーコンポーネントが1つある可能性があります)
Michelle Tilley

@MichelleTilley「フラックスのコアコンセプトの1つは、カスケードディスパッチを防ぎ、一度に複数のディスパッチを防ぐことです。これは、ストアが非同期処理を行う場合は非常に困難です。」それが私にとって重要なポイントです。よく言った。

51

私はこの質問をFacebookの開発者にツイートしました。ビルフィッシャーから得た答えは次のとおりです。

ユーザーによるUIの操作に応答するとき、アクションクリエーターメソッドで非同期呼び出しを行います。

ただし、ティッカーや人間以外の運転手がいる場合は、店からの電話の方がうまくいきます。

重要なことは、エラー/成功のコールバックでアクションを作成し、データが常にアクションで発生するようにすることです


これは理にかなっていますが、なぜa call from store works better when action triggers from non-human driver ですか?
SharpCoder 2016年

@SharpCoderライブティッカーなどがある場合、実際にアクションを実行する必要はありません。ストアからそれを実行する場合、ストアは即座に状態にアクセスできるため、おそらく少ないコードを記述する必要があります。 &変更を送信します。
Florian Wendelborn 2016

8

ストアは、データのフェッチや、ストアのデータが更新されたことをコンポーネントに通知することなど、すべてを行う必要があります。どうして?アクションは、重要な動作に影響を与えることなく、軽量、使い捨て、交換が可能になるためです。すべての重要な動作と機能はストアで発生します。これにより、非常に類似しているが異なる2つのアクションでコピーされる動作の重複も防止されます。ストアは、真実(の取り扱い)の唯一の情報源です。

すべてのFlux実装で、アクションは基本的にオブジェクトに変換されたイベント文字列であることを確認しました。従来、「anchor:clicked」という名前のイベントがありましたが、FluxではAnchorActions.Clickedとして定義されていました。それらは非常に「ダム」であるため、ほとんどの実装では、リスンしているストアにイベントを実際にディスパッチするための個別のDispatcherオブジェクトがあります。

個人的には、個別のDispatcherオブジェクトがなく、Actionオブジェクトがディスパッチを行うFluxのRefluxの実装が好きです。


編集:FacebookのFluxは実際には「アクションクリエーター」をフェッチするため、スマートアクションを使用します。また、ストアを使用してペイロードを準備します。

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/actions/ChatMessageActionCreators.js#L27(27行目と28行目)

次に、完了時のコールバックは、フェッチされたデータをペイロードとして使用して、新しいアクションをトリガーします。

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

だから私はそれがより良い解決策だと思います。


このReflux実装とは何ですか?聞いたことがありません。あなたの答えは面白いです。ストアの実装には、API呼び出しなどを実行するロジックが必要であることを意味しますか?ストアはデータを受信し、値を更新するだけでよいと思いました。特定のアクションにフィルターをかけ、ストアの一部の属性を更新します。
Jeremy D

Refluxは、FacebookのFluxのわずかなバリエーションです。github.com / spoike / refluxjsストアは、アプリケーションの「モデル」ドメイン全体を管理しますが、アクション/ディスパッチャは、物事をつなぎ合わせて接着するだけです。
Rygu 2014

1
だから私はこれについてもう少し考えて、自分の質問に(ほぼ)答えました。私はそれを(他の人が投票するための)回答としてここに追加しましたが、どうやら私はスタックオーバーフローでカルマが少なすぎて、まだ回答を投稿できません。だからここにリンクがあります:groups.google.com/d/msg/reactjs/PpsvVPvhBbc/BZoG-bFeOwoJ
plaxdan

グーグルグループのリンクをありがとう、それは本当に有益なようです。私はまた、ディスパッチャーを通過するすべてのものと、ストア内の本当にシンプルなロジックのファンです。基本的に、すべてのデータを更新します。@Rygu逆流をチェックします。
ジェレミーD

別のビューで回答を編集しました。両方の解決策が可能であるようです。ほぼ間違いなく、Facebookのソリューションを他のソリューションよりも優先して選びます。
Rygu

3

「ばかげた」アクションを支持する議論を提供します。

アクションでビューデータを収集する責任を負うことにより、アクションをビューのデータ要件に結び付けます。

対照的に、ユーザーの意図またはアプリケーションの状態遷移を宣言的に説明する一般的なアクションでは、そのアクションに応答するすべてのストアが、意図を、サブスクライブするビューに合わせて特別に調整された状態に変換できます。

これは、より多くの、しかしより小さく、より専門的なストアに役立ちます。私はこのスタイルを主張します

  • これにより、ビューがストアデータを使用する方法の柔軟性が高まります。
  • それらを使用するビューに特化した「スマート」ストアは、潜在的に多くのビューが依存する「スマート」アクションよりも小さく、複雑なアプリの結合が少なくなります

ストアの目的は、ビューにデータを提供することです。「アクション」という名前は、その目的がアプリケーションの変更を説明することであることを示唆しています。

ウィジェットを既存のダッシュボードビューに追加する必要があるとします。これは、バックエンドチームがロールアウトしたばかりのファンシーな新しい集計データを示しています。

「スマート」アクションでは、新しいAPIを使用するために「リフレッシュダッシュボード」アクションを変更する必要がある場合があります。ただし、抽象的な意味での「ダッシュボードの更新」は変更されていません。ビューのデータ要件は、変更されたものです。

「ダム」アクションを使用すると、新しいウィジェットが消費する新しいストアを追加し、「リフレッシュダッシュボード」アクションタイプを受信したときに新しいデータのリクエストを送信してそれを公開するように設定できます。準備ができたら、新しいウィジェット。ビューレイヤーがより多くのまたは異なるデータを必要とする場合、私が変更するものはそのデータのソースであるということは私には理にかなっています:ストア。


2

gaeronのflux-react-router-demoには、「正しい」アプローチの便利なバリエーションがあります。

ActionCreatorは外部APIサービスからpromiseを生成し、promiseと3つのアクション定数をdispatchAsyncプロキシ/拡張Dispatcherの関数に渡します。dispatchAsync常に最初のアクション(例: 'GET_EXTERNAL_DATA')をディスパッチし、Promiseが戻ると、 'GET_EXTERNAL_DATA_SUCCESS'または 'GET_EXTERNAL_DATA_ERROR'をディスパッチします。


1

ある日、Bret Victorの有名なビデオのInventing on Principleに見られるものに匹敵する開発環境が必要な場合は、副作用のない、データ構造内のアクション/イベントの単なる投影であるダムストアを使用する必要があります。また、実際にストアがReduxのように同じグローバル不変データ構造のメンバーである場合にも役立ちます。

詳細はこちら:https ://stackoverflow.com/a/31388262/82609

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