を発生した場合、私は2番目のワークフロー(ログイン)で打撃を与えるだろう。
コードに入る前に、redux-loop
は、よりシンプルであり、非同期制御の流れに関してredux-saga
よりも少ないことに注意してください。しかし、Elm
の精神で、データフローに重点が置かれています。したがって、静的に型指定された言語の観点から考えることは有益です。 Haskell
またはElm
では、それはおそらく自体は、ステートマシンをエンコードするデータの種類によって問題をモデル化することが有益だ:
data
と
err
は型変数です
data LoginStatus data err =
LoggedOut |
, LoggedIn data |
, LoginError err |
, Pending
は、ログインデータ型(トークン)とログインエラーを表します。動的に型定義されたJavaScriptには、同じ考えを表現する利点はありませんが、LoginStatus
のようなタグ付きユニオンタイプを模倣するために使用できるダイナミックな技がたくさんあります。ここで
import {match} from "single-key";
export default function reducer(state, action) {
return match(state, {
LoggedOut :() => loggedOutReducer(state, action),
LoggedIn :() => loggedInReducer(state, action),
Pending :() => pendingReducer(state, action),
LoginError :() => loginErrorReducer(state, action)
});
}
は、私は非常に基本的なランタイム共用体型を達成するために、シンプルであまり知られていないライブラリsinge-keyを使用します。さらに前がなければ、ここのコードです。名前が示す「単一キー」オブジェクトは、{ a: 1 }
(「a」がキー、1が値)など、キーと値だけを持つオブジェクトです。単一キーオブジェクトを使用して状態をモデル化します。異なるキーはLoginStatus
の異なるバリアントを表します。いくつかの例では、状態:これらは時々のデータを除いて、有限状態マシンの遷移のようなもの
// state :: { LoggedIn: {/* some data * } }
function loggedInReducer(state, action) {
if (action.type === LOGOUT) {
return {
LoggedOut : true
};
}
return state;
}
// state :: { Pending : true }
function pendingReducer(state, action) {
if (action.type === LOGIN_SUCCESS) {
return {
LoggedIn : {
token : action.payload.token,
user : action.payload.user
}
};
}
if (action.type === LOGIN_ERROR) {
return {
LoginError : action.payload;
};
}
if (action.type === LOGOUT) {
return {
LoggedOut : true
};
}
return state;
}
// state :: { LoggedOut : true }
function loggedOutReducer(state, action) {
if (action.type === LOGIN) {
return loop({ Pending: true }, Effects.promise(loginRequest));
}
return state;
}
// state :: { LoginError : error }
function loginErrorReducer(state, action) {
if (action.type === LOGIN) {
return loop({ Pending: true }, Effects.promise(loginRequest));
}
return { LoggedOut : true };
}
:片付けことで
{
LoggedOut : true
}
{
LoggedIn : {
token : 1235,
user : { firstName: "John" }
}
}
{
Pending : true
}
が、ここでの主な減速に使用されるサブ減速しています状態に付いている。個々のレデューサーはかなりシンプルで、アクションタイプはほとんどありません。 - redux-loop
によってスケジュールされます。これは、Pending
にLoggedOut
/LoginError
からの状態を遷移し、いくつかの副作用を指定
return loop({ Pending: true }, Effects.promise(loginRequest));
:2つだけ減速が影響を返します。あなたは2つのバリアントを1つに統合することもできます:{ LoggedOut : error | null }
しかし、私は別々の状態を持っていると感じます。長期的には有益な状態です。
データ型の概念によっては、この問題は最初に現れるよりも簡単に判断することができます。あなたは同じものを同じように構成することができます減速器はほぼ同じ構造とredux-thunk
を使用して構造化されています。
私はこの回答に感謝しますが、このアプローチの問題は、それが責任を混同していることです。非同期ワークフロー+「通常の」状態。これは複雑な減速器につながる。実際のプロジェクトでは、脆弱なコードを簡単に作成できるようになりました。また、上記のワークフローを実際に実行する方法についても説明していません。 –
フィードバックいただきありがとうございます。これは妥当な批判です。最後の点については、私はそれがどのように機能するかについて主に取り組んできたと信じています。さて、私は今日、いくつかの自由時間があるので、ここで説明した減速機のレイアウトを使った実例を作っただけです。これは、ほぼ同一のレデューサーを持つ 'redux-loop'と' redux-sage'の両方の実装を持っています:[https://github.com/yiransheng/redux-login-examples](https://github.com/yiransheng/redux -login-examples) –
明示的に型を列挙するのは良い考えです。残念なことに、彼らがアメリカで言うように、 "あなたは死んだ馬を打っています。"さらに、懸案事項の混在には、非同期性を扱うための専用APIはありません。したがって、現実の世界のプロジェクトでは、コードは非常に複雑になります(繰り返します)。たとえば、「キャンセル」の場合は処理しません。第二に、FRP /サガはテストで勝つ。モックは必要ありません。 –