Redux-複数の店舗、なぜそうではないのですか?


221

注:私はRedux(Baobabも)のドキュメントを読み、グーグルとテストのかなりの部分を行いました。

Reduxアプリにストアが1つしかないことが強く推奨されているのはなぜですか?

私は、単一ストアのセットアップと複数ストアのセットアップの長所/短所を理解しています(このテーマについては、SOに関する多くのQ&Aがあります)。

IMO、このアーキテクチャ上の決定は、プロジェクトのニーズに基づいてアプリ開発者に属しています。では、なぜそれがとても強くReduxのため、ほとんど必須鳴らすのポイントに提案されている(何もかかわらず、複数の店舗を作るから私たちを停止していますか)?

編集:シングルストアに変換した後のフィードバック

多くの人が複雑なSPAと考えるものについてreduxで作業した数か月後、単一のストア構造で作業することは純粋に嬉しかったと言えます。

単一のストアと多くのストアが多くの多くのユースケースで根本的な問題である理由を他の人が理解するのに役立ついくつかのポイント:

  • 信頼性があります。セレクターを使用してアプリの状態を調べ、コンテキストに関連する情報を取得します。必要なすべてのデータが1つのストアにあることがわかっています。それは、州の問題がどこにあり得るかについてのすべての質問を避けます。
  • それは速いです:私たちの店は現在、100以上の減速機を持っています。その数でさえ、ごく一部のレデューサーのみが特定のディスパッチのデータを処理し、他のレデューサーは以前の状態を返します。巨大/複雑なストア(reducerのnbr)が遅いという主張は、かなり根拠のないものです。少なくともそこからパフォーマンスの問題が発生することはありません。
  • デバッグしやすい:これは全体としてreduxを使用するのに最も説得力のある引数ですが、シングルストアとマルチストアのどちらにも当てはまります。プロセスで状態エラー(プログラマーのミス)が発生することになっているアプリをビルドする場合、それは正常です。PITAは、これらのエラーのデバッグに数時間かかる場合です。単一のストア(およびredux-logger)のおかげで、特定の状態の問題に数分以上費やすことはありませんでした。

いくつかのポインタ

reduxストアの構築における真の課題は、それをどのように構成するかを決定するときです。第一に、将来の構造変更はただの大きな痛みなのでです。第二に、それは主に使用方法を決定し、あらゆるプロセスのアプリデータをクエリするためです。ストアの構成方法については、多くの提案があります。私たちの場合、次のことが理想的であることがわかりました。

{
  apis: {     // data from various services
    api1: {},
    api2: {},
    ...
  }, 
  components: {} // UI state data for each widget, component, you name it 
  session: {} // session-specific information
}

このフィードバックが他の人に役立つことを願っています。

編集2-役立つストアツール

単一のストアを「簡単に」管理する方法を疑問に思っている方は、すぐに複雑になる可能性があります。ストアの構造的な依存関係/ロジックを分離するのに役立つツールがあります。

スキーマに基づいてデータを正規化するNormalizrがあります。次にid、辞書と同様に、データを操作し、によってデータの他の部分をフェッチするためのインターフェースを提供します。

当時のNormalizrを知らなかったので、同じように何かを作りました。relational-jsonはスキーマを受け取り、テーブルベースのインターフェースを返します(データベースに少し似ています)。Relational-jsonの利点は、データ構造がデータの他の部分を動的に参照することです基本的に、通常のJSオブジェクトと同様に、データを任意の方向にトラバースできます)。それはNormalizrほど成熟していませんが、私は数か月間、本番環境で正常に使用しています。


4
私はあなたが使っている店舗構造に対するあなたのアプローチが好きです。ただし、コンポーネントの状態の変化にマッピングするAPIの状態の変化をどのように処理しますか?それで、APIからドメイン固有のデータを受け取ったとしましょう。これは、コンポーネントにある一般的なデータ構造にどのように変換されますか?
Diniden

コンポーネントがどのようにマップ/ストアデータを使用するかは、あなた次第です。あなたの質問は完全には理解できていないと思いますが、チャットセッションについて詳しく説明したり、開始したりできますか
Sebastien Daniel

2
問題は、コンポーネントがapis状態からレンダリングするのか、それともコンポーネント状態に入れられたものだけをレンダリングするのかだと思います。コンポーネントの状態からのみレンダリングできたとしたら、ドメイン固有のデータが存在する場合でもコンポーネントとコンテナを再利用可能にする優れた方法を見つけたと思います。コンポーネントがAPI状態とコンポーネント状態から部分的にレンダリングしている場合、ドメイン固有のコンテナーを使用して、APIのデータを、コンポーネントが理解する一般的なリストとプリミティブにマッピングしていると思います。
Diniden

2
Reduxをセレクターと組み合わせて使用​​します。セレクターは基本的に機能的に純粋なデータマッパーとしてメモ化されています。各コンポーネントは、更新を格納するために「反応」し、変更がそれに関連する場合、データを「選択」し、それに応じてレンダリングします。つまり、コンポーネントは、それらにとって重要なものに基づいてのみレンダリングします。しかし、それはReduxやストア構造だけが原因ではありません。これは、不変データストア、データ変更の参照比較テスト、およびコンポーネントが必要とするデータをコンポーネントが必要とする形式でフェッチする純粋なセレクターの組み合わせによるものです。
セバスチャンダニエル

@SebastienDanielさん、ストアの更新の変更が関連しているかどうかを確認するために各コンポーネントが行うチェックを実装する方法の例を示していただけますか?つまり、ある種の一般的なパターンを使用している場合や、特定の場合ごとに、特定のコンポーネント関連データが変更されているかどうかを確認している場合です。
John

回答:


232

複数のストアを使用する可能性のあるエッジケースがあります(たとえば、画面に表示されている数千のアイテムのリストを1秒間に何回も更新することでパフォーマンスの問題がある場合)。とはいえ、これは例外であり、ほとんどのアプリでは、単一のストア以上のものは必要ありません。

ドキュメントでこれを強調するのはなぜですか?Fluxのバックグラウンドを持っているほとんどの人は、複数のストアが更新コードをモジュール化するためのソリューションである想定しているためです。ただし、Reduxにはこのための別のソリューションがあります。それは、レデューサーコンポジションです。

複数のレデューサーをレデューサーツリーにさらに分割することは、Reduxでモジュール式の更新を維持する方法です。これを認識せず、最初にレデューサーの構成を完全に理解せずに複数のストアに行くと、Reduxシングルストアアーキテクチャの多くの利点を見逃してしまいます。

  • レデューサー構成を使用するとwaitFor、追加情報を使用して特定の順序で他のレデューサーを手動で呼び出すレデューサーを記述することにより、Fluxの「依存更新」を簡単に実装できます。

  • 単一のストアを使用すると、状態を保持、ハイドレート、および読み取るのが非常に簡単です。サーバーでのレンダリングとデータのプリフェッチは、クライアントにデータを入力して再水和する必要があるのは1つだけなので、JSONはストアのIDや名前を気にすることなくその内容を記述できます。

  • 単一のストアがRedux DevToolsのタイムトラベル機能を可能にします。また、redux-undoやredux-optimistなどのコミュニティ拡張機能は、レデューサーレベルで動作するため、簡単になります。このような「還元剤エンハンサー」は、店舗向けに作成することはできません。

  • 単一のストアは、ディスパッチが処理された後にのみサブスクリプションが呼び出されることを保証します。つまり、リスナーに通知されるまでに、状態は完全に更新されています。多くの店舗では、そのような保証はありません。これがFluxがwaitFor松葉杖を必要とする理由の1つです。単一のストアでは、これは最初から目にする問題ではありません。

  • 何よりも、Reduxでは複数のストアは不要です(とにかく最初にプロファイリングすることになっているパフォーマンスエッジのケースを除きます)。私たちはそれをドキュメントの重要なポイントにしていますので、ReduxをFluxであるかのように使用してその利点を失う代わりに、レデューサーの構成と他のReduxパターンを学ぶことをお勧めします。


11
レジューサー構成の利点/必要性を完全に理解していなかったことを認めます。あなたの答えのおかげで、私はもう少し読んで例を出しました(TodoMVCも)。このような小さな例では、レジューサー組成物によって提供される実際の改善を理解するのは困難でした。しかし、少し考えてみると、大規模な場合の利益は(現在)明白です。ありがとうございます。すばらしい回答です。
セバスチャンダニエル

4
@Sebastien「ショッピングカート」の例のほうがいいと思います。
Dan Abramov、2015年

3
従来の(非SPA)アプリケーションにreduxをゆっくりと実装しています。アプリ全体を変更して同じストアを使用できるようになるまで、react / redux実装に変換する「全体」ごとにmultilpeストアを使用しています。
Paul Knopf

5
@DanAbramovメインの「アプリ」が独自のReduxストアを実行していて、npmを介して独自のReduxストアを実行するスタンドアロンの「アプリ」をインポートしている状況でのあなたの見方を知りたいです。たとえば、社内の他のチームの1つが、そのデータでストアを汚染することなくプルしたいUIを備えたメッセージングサービスの種類を持っている場合。
natlee75 2016

6
@ natlee75「Reduxで複数のストアを使用するいくつかの有効な理由は次のとおりです。[...]より大きなアプリケーションのコンポーネントとしてReduxアプリを分離する場合、ルートコンポーネントインスタンスごとにストアを作成することができます。」redux.js.org/docs/FAQ.html#store-setup-multiple-stores
ケビン

24

数百または数千のレデューサーを備えた一部の非常に大規模なエンタープライズアプリでは、アプリのさまざまな領域を完全に別個のアプリと考えると便利な場合があります。そのような場合(実際にはドメイン名を共有する複数のアプリです)、複数のストアを使用します。

たとえば、次の一般的な機能領域を個別のアプリとして扱う傾向があります。

  • 管理者
  • 分析/データダッシュボード
  • 課金管理と購入フロー
  • エンタープライズアカウントチーム/権限管理

それらのいずれかが小さい場合は、メインアプリの一部として保持してください。それらが非常に大きくなる場合(一部のエンタープライズアカウント管理および分析ツールのように)、それらを分割します。

非常に大きなアプリを管理する最良の方法は、それらを多くの小さなアプリの構成のように扱うことです。

アプリのLOCが約50k未満の場合は、このアドバイスを無視して、代わりにDanのアドバイスに従う必要があります。

アプリのLOCが100万を超える場合は、ミニアプリをモノリポジトリで維持していても、おそらく分割する必要があります。


5

このアーキテクチャ上の決定は、プロジェクトのニーズに基づいてアプリ開発者に属しています

あなたは自分の世界に住んでいます。reduxを利用している人との出会いです。人気があるからです。どのくらいのプロジェクトが何の決定もなくやり直しを始めたとは想像もできませんでした。他の開発者は他に何も知らないので、私はreduxアプローチが嫌いですが、それを使わなければなりませんでした。これは、facebookで膨らまされた壮大なバブルです。

  • 店舗の一部が隔離されていないため、信頼性がありません。
  • ハッシュトライをクローンしてトラバースするため、非効率的です。突然変異が算術的に増大するとき-複雑さは幾何学的に増大します。リデューサー、セレクターなどをリファクタリングしても修正できません。トライを分割する必要があります。
  • 遅くなると、誰もそれを別々のストアを持つ別々のアプリケーションに分割したくありません。誰もがリファクタリングにお金を費やすことを望んでいません。人々は通常、いくつかのスマートコンポーネントをダンプに変換していますが、それだけです。redux開発者を待っている未来を知っていますか?彼らはこれらの地獄を維持します。
  • フレンドリーなデバッグではありません。ストアの実質的に分離された部分間の接続をデバッグするのは困難です。これらの接続の量を分析することさえ非常に困難です。

複数のreduxストアがあるとします。単方向のデータフローが壊れます。あなたはすぐにあなたが持っている店の間のどれだけのつながりを理解するでしょう。あなたはこれらのつながり、循環部隊との戦いなどに苦しむことができます。

一方向のフローを備えた単一の不変ストアは、すべての病気のエリクサーというわけではありません。プロジェクトアーキテクチャを維持したくない場合は、とにかく苦労します。


私はあなたの言ったことが好きで、ここでこれに関連する質問をしました。少し時間があるときにこれを見て、意見を共有していただけませんか。私がRedditで質問したのは、SOがそのような質問をここで推奨していないためです。
Arup Rakshit

3

次の使用例では、複数のストアが役立ちます。1.データ構造、動作、アプリケーションコンテキストの点で互いに独立している大きなコンポーネントがある場合。これらのコンポーネントを分離すると、データとアプリケーションフローの管理が容易になります。また、コンポーネントの独立した開発とメンテナンスにも役立ちます。2.パフォーマンスの問題:典型的な使用例ではありませんが、コンポーネントの一部が非常に頻繁に更新され、他のコンポーネントに影響がない場合は、おそらく別のストアに行くことができます。

他のすべてのケースでは、複数のストアを持つ必要がない場合があります。ダンが言うように、思慮深いレデューサー組成を作成することは、より良い解決策であると証明することができます。


メッセージは、「少数の場合を除いて常にreduxを使用する」==「少数の場合を除いてプロジェクトアーキテクチャは必要ない」のようになります。現実にとても近いです。
puchu

2

reduxを使用して複数のストアを使用できないのはなぜですか?

データドメイン間の分離は、単一のレデューサーをより小さなレデューサーに分割することですでに実現されているため、これはReduxでは必要ありません。


複数のストアを作成できますか?ストアを直接インポートして、自分でコンポーネントで使用できますか?

元のFluxパターンは、アプリに複数の「ストア」があり、それぞれがドメインデータの異なる領域を保持していることを示していました。これにより、1つのストアを更新するために別のストアを「待機」する必要があるなどの問題が発生する可能性があります。

データドメイン間の分離は、単一のレデューサーをより小さなレデューサーに分割することですでに実現されているため、これはReduxでは必要ありません。

他のいくつかの質問と同様に、ページに複数の異なるReduxストアを作成することは可能ですが、意図されたパターンは単一のストアのみを持つことです。ストアを1つにすると、Redux DevToolsを使用できるようになり、データの永続化と再水和が簡単になり、サブスクリプションロジックが簡素化されます。

Reduxで複数のストアを使用する有効な理由には、次のものがあります。

アプリのプロファイリングによって確認されたときに、状態の一部の頻繁な更新によって引き起こされるパフォーマンスの問題を解決します。より大きなアプリケーションのコンポーネントとしてReduxアプリを分離する。この場合、ルートコンポーネントインスタンスごとにストアを作成することができます。ただし、特にFluxのバックグラウンドを持っている場合は、新しいストアを作成することが最初の本能であってはなりません。最初にレデューサー構成を試してください。問題が解決しない場合にのみ、複数のストアを使用してください。

同様に、ストアインスタンスを直接インポートすることで参照できますが、これはReduxでの推奨パターンではありません。ストアインスタンスを作成してモジュールからエクスポートすると、シングルトンになります。つまり、サーバー上ではリクエストごとに個別のストアインスタンスを作成する必要があるため、Reduxアプリを大きなアプリのコンポーネントとして分離することや、サーバーレンダリングを有効にすることが難しくなります。

reduxによる公式ドキュメント


1

Reduxに1つの店舗を持つことは、多くの場合私たちが必要とするものです。私はReduxとFluxの両方を使用しており、Reduxがうまく機能すると信じています!

ストアがJavaScriptオブジェクト内にあることを忘れないでください。ストアは1つしかありませんが、簡単に拡張して再利用できます。1つのストアを用意することで、Redux開発ツールを使用したトラバースがはるかに簡単になり、混同することがなくなります。大きなアプリケーション...

また、1つのストアの概念はデータベースを模倣しています。これは、変更でき、ブラウザのメモリでアクセスできる真実の1つの情報源です...

アプリケーション全体が適切に管理されている場合、1つのストアでアプリケーション全体のステータスを管理できます...


3
したがって、誰もが単一の店がより良い仕事をするだろうと信じるべきであり、誰もその理由を説明することはできません。それは私に何かを思い出させます...
ぷち
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.