Fluxアーキテクチャでは、Storeのライフサイクルをどのように管理するのですか?
Flux]1を読んでいますが、Todoアプリの例があまりにも単純すぎて、いくつかの重要なポイントを理解することができません。
Facebookのような、ユーザープロファイルページを持つシングルページアプリを想像してください。各ユーザープロファイルページでは、ユーザ情報と直近の投稿を、無限スクロールで表示したいと思います。あるユーザープロファイルから別のユーザープロファイルに移動することができます。
Fluxのアーキテクチャでは、これはStoreとDispatcherにどう対応するのでしょうか?
ユーザーごとに1つの PostStore
を使うのか、それともある種のグローバルなストアを持つのか? ディスパッチャについては、「ユーザーページ」ごとに新しいディスパッチャを作成するのか、それともシングルトンを使用するのか?最後に、ルート変更に対応する「ページ固有の」ストアのライフサイクルを管理するのは、アーキテクチャのどの部分でしょうか?
さらに、1つの擬似ページが、同じ型のデータのリストを複数持つことがあります。例えば、プロフィールページで、FollowersとFollowsの両方を表示したいです。この場合、シングルトンの UserStore
はどのように機能するのでしょうか?UserPageStoreは
followedBy.UserStoreを管理するのでしょうか?UserStore
と follows:UserStore
は管理できますか?
132
3
Fluxアプリでは、Dispatcherは1つだけであるべきです。 すべてのデータはこの中心的なハブを経由して流れます。 シングルトンのDispatcherを持つことで、すべてのStoreを管理することができます。 これは、Store #1が自身を更新し、Store #2がActionとStore #1の状態の両方を基に自身を更新する必要がある場合に重要になります。 Fluxは、このような状況が大規模なアプリケーションで起こりうることを想定しています。 理想を言えば、このような状況は発生する必要がなく、開発者は可能であればこのような複雑な状況を避けるように努力すべきです。 しかし、シングルトンDispatcherは、いざというときに対処できるようになっています。
ストアも同様にシングルトンです。 ストアは可能な限り独立かつ非結合のままであるべきで、Controller-Viewから問い合わせることができる自己完結した宇宙です。 ストアに入るには、ディスパッチャに登録されたコールバックを経由する必要があります。 Storeに入るには、Dispatcherに登録したコールバックを経由し、出るにはゲッター関数を経由します。 Storeは状態が変化したときにイベントも発行するので、Controller-Viewはゲッターを使って新しい状態を問い合わせるタイミングを知ることができます。
この例では、1つの
PostStore
が存在することになります。 この同じストアで、FB のニュースフィードのようなページ(疑似ページ)の投稿を管理できます。 論理的なドメインは投稿のリストであり、どんな投稿のリストも扱うことができます。 擬似ページから擬似ページに移行する際には、新しい状態を反映させるために、ストアの状態を再初期化したいと思います。 擬似ページ間を行き来するための最適化として、以前の状態をlocalStorageにキャッシュすることもできますが、私の考えでは、他のすべてのストアを待ち、擬似ページ上のすべてのストアについてlocalStorageとの関係を管理し、それから自身の状態を更新するPageStore
をセットアップすることをお勧めします。 このPageStore
は投稿については何も保存しないことに注意してください -- それはPostStore
の領域です。 これは単に、特定の擬似ページがキャッシュされているかどうかを知っているだけです。なぜなら、擬似ページはそのドメインだからです。PostStore
は
initialize()メソッドを持っています。 このメソッドは、たとえ最初の初期化であっても、常に古い状態をクリアし、Actionを通して受け取ったデータに基づいて、Dispatcherを介して状態を作成することになる。 ある疑似ページから別の疑似ページへの移動には、おそらく
PAGE_UPDATEアクションが必要で、これが
initialize()` の起動のトリガーとなるでしょう。 ローカルキャッシュからのデータ取得、サーバーからのデータ取得、楽観的なレンダリング、XHRエラーの状態などの詳細な作業が必要ですが、これが一般的なアイデアです。もし、特定の擬似ページがアプリケーション内のすべてのストアを必要としないのであれば、メモリの制約以外に、未使用のストアを破棄する理由があるとは全く思えません。 しかし、ストアは通常、大量のメモリを消費するわけではありません。 ただ、破棄するController-Viewsのイベントリスナーを確実に削除する必要があります。 これはReactの
componentWillUnmount()
メソッドで行われます。(注:JSX Harmonyオプションを使用して、ES6構文を使用しています)。
練習として、
Github users
とreposをブラウズできる sample Flux app を書きました。これはfisherwebdev's answerに基づいていますが、私がAPIのレスポンスを正規化するために使っているアプローチも反映しています。
Fluxの学習中に私が試したいくつかのアプローチを記録するために作りました。
現実の世界に近づけようとしました(ページネーション、偽のlocalStorage APIを使わない)。
この中で、特に興味を持った部分がいくつかあります。
switch
です;ストアの分類方法
他のFluxの例で見た、特にStoresの重複を避けようとしました。 特にStoresについては、他のFluxの例で見られたような重複を避けるようにしました。Storesを論理的に3つのカテゴリーに分けることが有効であると考えました。
コンテンツストアは、すべてのアプリのエンティティを格納します。コンテンツストア**は、すべてのアプリのエンティティを保持します。IDを持つすべてのものは、それ自身のコンテンツストアが必要です。個々のアイテムをレンダリングするコンポーネントは、新鮮なデータをコンテンツ ストアに要求します。
コンテンツ ストアは すべての サーバー アクションからオブジェクトを取得します。例えば、
UserStore
はaction.response.entities.users
が存在すれば、どのアクションが実行されたかに関係なく、そのオブジェクトを取得することができます。スイッチ`は必要ありません。Normalizr を使えば、どんなAPIレスポンスも簡単にこの形式にすることができます。リストストア は、グローバルなリスト (例: "feed", "your notifications") に出現するエンティティの ID を記録します。このプロジェクトでは、そのようなストアはありませんが、とりあえず触れておこうと思います。これらはページネーションを扱います。
通常、いくつかのアクション(例:
REQUEST_FEED
,REQUEST_FEED_SUCCESS
,REQUEST_FEED_ERROR
)に反応するだけです。インデックス付きリストストア はリストストアに似ていますが、1対多のリレーションシップを定義します。例えば、"user's subscribers", "repository's stargazers", "user's repositories "のような関係です。また、ページネーションも扱えます。
また、通常はいくつかのアクションに反応します (例:
REQUEST_USER_REPOS
、REQUEST_USER_REPOS_SUCCESS
、REQUEST_USER_REPOS_ERROR
など)。ほとんどのソーシャルアプリでは、このようなものがたくさんあり、それらのうちの1つを素早く作成できるようにしたいと思うでしょう。
注:これらは実際のクラスなどではなく、私がStoreについて考えたい方法です。 でも、いくつかヘルパーを作りました。
StoreUtils
createStore
(ストア作成)このメソッドは、最も基本的なStoreを提供します。
私はすべてのStoreを作成するためにこの方法を使用しています。
isInBag
,mergeIntoBag
.コンテンツストアに便利な小さなヘルパーです。
PaginatedList
ページ送りの状態を保存し、特定のアサーション(can't fetch during fetch page, etc)を強制する。
PaginatedStoreUtils
createListStore
,createIndexedListStore
,createListActionHandler
を作成する。定型的なメソッドとアクション処理を提供することで、 Indexed List Store の作成を可能な限りシンプルにします。
createStoreMixin
コンポーネントが興味のあるStoreにチューニングするためのMixinです。例:
mixins: [createStoreMixin(UserStore)]
.そこでRefluxでは、Dispatcherの概念を取り除き、アクションとストアによるデータフローだけで考えるようにしました。すなわち