Redux FAQ: アクション
目次
- Redux FAQ: アクション
アクション
なぜ type
は文字列であるべきなのか?なぜアクションタイプは定数であるべきなのか?
状態と同様に、シリアライズ可能なアクションは、タイムトラベルデバッグやアクションの記録と再生など、Redux の定義的な機能のいくつかを実現します。type
値に Symbol
のようなものを使用したり、アクション自体に instanceof
チェックを使用したりすると、それが壊れてしまいます。文字列はシリアライズ可能で、簡単に自己記述できるため、より良い選択です。アクションがミドルウェアで使用されることを意図している場合、アクションで Symbols、Promises、またはその他のシリアライズ不可能な値を使用しても*問題ない*ことに注意してください。アクションは、実際にストアに到達し、リデューサーに渡されるまでにシリアライズ可能であるだけでよいのです。
パフォーマンス上の理由から、シリアライズ可能なアクションを確実に強制することはできないため、Redux はすべてのアクションがプレーンなオブジェクトであることと、type
が文字列であることをチェックするだけです。残りはあなた次第ですが、すべてをシリアライズ可能にしておくと、デバッグや問題の再現に役立つ可能性があります。
一般的に使用されるコードをカプセル化して集中化することは、プログラミングにおける重要な概念です。どこでも手動でアクションオブジェクトを作成し、各 type
値を手書きすることは確かに可能ですが、再利用可能な定数を定義すると、コードのメンテナンスが容易になります。定数を別のファイルに配置すると、import
ステートメントのスペルミスをチェックして、誤った文字列を誤って使用しないようにすることができます。
さらに詳しい情報
ドキュメント
議論
- #384: アクション定数は過去形で命名することを推奨
- #628: ボイラープレートの少ない簡単なアクション作成の解決策
- #1024: 提案:宣言的なリデューサー
- #1167: switch を使用しないリデューサー
- Stack Overflow: なぜ Redux ではデータとして「アクション」が必要なのですか?
- Stack Overflow: Redux の定数のポイントは何ですか?
リデューサーとアクションの間には常に一対一のマッピングがあるのか?
いいえ。ステートの特定のスライスへの更新を担当する、独立した小さなリデューサー関数を作成することをお勧めします。このパターンを「リデューサー合成」と呼びます。特定のアクションは、すべて、一部、またはどれも処理しない可能性があります。これにより、コンポーネントは実際のデータ変更から分離されます。1つのアクションが状態ツリーの異なる部分に影響を与える可能性があり、コンポーネントがこれを認識する必要がないためです。一部のユーザーは、「ダックス」ファイル構造のように、それらをより緊密にバインドすることを選択しますが、デフォルトでは一対一のマッピングは間違いなくなく、多くの場合にリデューサーでアクションを処理したい場合は、そのようなパラダイムを破る必要があります。
さらに詳しい情報
ドキュメント
ディスカッション
- Twitter:最も一般的な Redux の誤解
- #1167: switch を使用しないリデューサー
- Reduxible #8:リデューサーとアクションクリエーターは一対一のマッピングではない
- Stack Overflow: Redux Thunk ミドルウェアなしで複数のアクションをディスパッチできますか?
AJAX 呼び出しなどの「副作用」をどのように表現できるのか?なぜ非同期処理を行うために「アクションクリエーター」、「サンク」、「ミドルウェア」のようなものが必要なのか?
これは長く複雑なトピックであり、コードをどのように整理し、どのようなアプローチを使用すべきかについてさまざまな意見があります。
意味のある Web アプリは、通常、AJAX リクエストを行うなどの非同期作業を含む複雑なロジックを実行する必要があります。そのコードはもはや純粋に入力の関数ではなくなり、外部世界との相互作用は 「副作用」として知られています。
Redux は関数型プログラミングに触発されており、そのままの状態では副作用を実行する場所がありません。特に、リデューサー関数は常に (state, action) => newState
の純粋関数で*なければなりません*。ただし、Redux のミドルウェアを使用すると、ディスパッチされたアクションをインターセプトし、副作用を含む追加の複雑な動作をアクションに追加することができます。
一般的に、Redux では、副作用のあるコードはアクション作成プロセスの一部であるべきであると考えています。そのロジックは UI コンポーネント内で実行できますが、通常は複数の場所から同じロジックを呼び出すことができるように、そのロジックを再利用可能な関数(つまり、アクションクリエーター関数)に抽出するのが理にかなっています。
これを行う最も簡単で一般的な方法は、Redux Thunk ミドルウェアを追加することです。これにより、より複雑な非同期ロジックを持つアクションクリエーターを記述できます。広く使用されている別の方法は Redux Saga で、ジェネレーターを使用してより同期的なコードを記述でき、Redux アプリで「バックグラウンドスレッド」または「デーモン」のように動作できます。さらに別のアプローチは Redux Loop で、状態の変化に応じて副作用を宣言し、それらを別々に実行できるようにすることでプロセスを反転させます。それ以外にも、副作用をどのように管理するかについて独自の見解を持つ、コミュニティで開発された*多数の*ライブラリやアイデアがあります。
さらに詳しい情報
ドキュメント
記事
- Redux の副作用とあなた
- Redux における純粋な機能と副作用
- Flux から Redux へ:簡単な非同期アクション
- React/Redux リンク:「Redux の副作用」カテゴリ
- Gist:Redux-Thunk の例
ディスカッション
- #291: API 呼び出しを適切な場所に配置しようとしています
- #455: 副作用のモデル化
- #533: 非同期アクションクリエーターの簡単な紹介
- #569: 提案:明示的な副作用のための API
- #1139: ジェネレーターとサガに基づく代替の副作用モデル
- Stack Overflow: Redux で非同期フローにミドルウェアが必要なのはなぜですか?
- Stack Overflow: タイムアウトで Redux アクションをディスパッチするには?
- Stack Overflow: Redux でアクションにリンクされた同期的な副作用はどこに配置すべきですか?
- Stack Overflow: Redux で複雑な副作用を処理するには?
- Stack Overflow: ajax レスポンスをモックするために非同期 Redux アクションを単体テストする方法
- Stack Overflow: Redux で状態の変化に応じて AJAX 呼び出しを発行するには?
- Reddit:Redux-Promise ミドルウェアを使用した非同期 API 呼び出しの実行をサポートします。
- Twitter: サガ、ループ、その他のアプローチ間の可能性のある比較
どの非同期ミドルウェアを使うべきか?サンク、サガ、オブザーバブル、またはその他のものの中からどのように選択するのか?
多数の非同期/副作用ミドルウェアが利用可能ですが、最も一般的に使用されているのは redux-thunk
、redux-saga
、および redux-observable
です。これらは異なるツールであり、それぞれ長所、短所、およびユースケースが異なります。
一般的な経験則として
- サンクは、複雑な同期ロジック(特に Redux ストアの状態全体へのアクセスを必要とするコード)と、単純な非同期ロジック(基本的な AJAX 呼び出しなど)に最適です。
async/await
を使用すると、サンクをより複雑な Promise ベースのロジックにも使用するのが合理的になります。 - サガは、複雑な非同期ロジックと、切り離された「バックグラウンドスレッド」タイプの動作に最適です。特に、ディスパッチされたアクションをリッスンする必要がある場合は(これはサンクでは実行できないことです)。これらを使用するには、ジェネレーター関数と
redux-saga
の「エフェクト」演算子に精通している必要があります。 - オブザーバブルはサガと同じ問題を解決しますが、非同期動作を実装するために RxJS に依存しています。これらを使用するには、RxJS API に精通している必要があります。
ほとんどの Redux ユーザーは、まずサンクから始め、アプリでより複雑な非同期ロジックの処理が本当に必要な場合は、後でサガやオブザーバブルなどの追加の副作用ライブラリを追加することをお勧めします。
サガとオブザーバブルには同じユースケースがあるため、アプリケーションは通常、どちらか一方を使用しますが、両方は使用しません。ただし、サンクとサガまたはオブザーバブルの両方を一緒に使用してもまったく問題ありません。これらは異なる問題を解決するためです。
記事
- Decembersoft: Redux で非同期操作を行う正しい方法は何ですか?
- Redux-Thunk vs Redux-Saga:概要
- Redux-Saga V.S. Redux-Observable
ディスカッション
- Reddit:サンクとサガを一緒に使用することの議論と、サガの長所と短所
- Stack Overflow: ES2015 ジェネレーターを使用した redux-saga と ES2017 async/await を使用した redux-thunk の長所/短所
- Stack Overflow: Redux-Saga の代わりに Redux-Observable を使用する理由は何ですか?
1つのアクションクリエーターから複数のアクションを連続してディスパッチするべきか?
アクションをどのように構成する必要があるかについての特定のルールはありません。Redux Thunk のような非同期ミドルウェアを使用すると、複数の個別の関連アクションを連続してディスパッチしたり、AJAX リクエストの進行状況を表すアクションをディスパッチしたり、状態に基づいて条件付きでアクションをディスパッチしたり、アクションをディスパッチしてその直後に更新された状態を確認したりするなどのシナリオが確実に可能になります。
一般的に、これらのアクションが関連しているが独立しているのか、それとも実際には1つのアクションとして表現すべきなのかを自問してください。ご自身の状況に合わせて判断するのが良いですが、リデューサーの可読性とアクションログの可読性のバランスを取るようにしてください。例えば、新しい状態ツリー全体を含むアクションは、リデューサーを1行にするでしょう。しかし、欠点は、変更がなぜ発生しているかの履歴がなくなるため、デバッグが非常に困難になることです。一方で、アクションを細かく保つためにループでアクションを発行する場合、それは異なる方法で処理される新しいアクションタイプを導入したい兆候かもしれません。
パフォーマンスが気になる箇所で、同期的に連続して複数回ディスパッチすることを避けてください。ディスパッチをまとめてバッチ処理できるアドオンやアプローチが多数存在します。
詳細情報
ドキュメント
記事
ディスカッション
- #597: イベントハンドラから複数のアクションをディスパッチするのは有効ですか?
- #959: 1回のディスパッチで複数のアクションを実行しますか?
- Stack Overflow: この非同期アクションを表現するために、1つまたは複数のアクションタイプを使用する必要がありますか?
- Stack Overflow: Reduxではイベントとアクションに1対1の関係がありますか?
- Stack Overflow: アクションは、関連するアクションのリデューサーによって処理されるべきですか、それともアクションクリエイター自身によって生成されるべきですか?
- Twitter: 「Redux Thunkの問題に関する良いスレッド...」