我会给在第二个工作流(登录)一杆。
在进入代码之前,值得注意的是redux-loop
比异步控制流程简单很多,并且提供了小于redux-saga
。但本着Elm
的精神,重点在于数据流 - 通常通过数据类型来实现这一点并不令人意外。因此,从静态类型语言的角度思考是有帮助的。在Haskell
或Elm
,这可能有利于模型的数据类型,其本身编码状态机的问题:
data LoginStatus data err =
LoggedOut |
, LoggedIn data |
, LoginError err |
, Pending
凡data
和err
是类型变量代表登录的数据类型(标记)和登录错误。 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
的不同变体。几个例子指出:
{
LoggedOut : true
}
{
LoggedIn : {
token : 1235,
user : { firstName: "John" }
}
}
{
Pending : true
}
随着该清理,这里是在主减速器使用的子减速器:
// 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 };
}
这些就像在有限状态机转变,除了有时与数据附属于该州。每个单独的reducer都相当简单,并且处理很少的动作类型。只有两个减速返回效果:
return loop({ Pending: true }, Effects.promise(loginRequest));
这种转变从LoggedOut
/LoginError
状态,以Pending
并指定一些副作用 - 这将由redux-loop
安排。你甚至可以将这两个变体合并为一个:{ LoggedOut : error | null }
,但是我觉得从长远来看,单独的LoginError
状态是有益的。
对于某些数据类型的概念,这个问题比第一次出现时更容易推理;你可以用减速机做同样的事情,结构大致相同,只用redux-thunk
。
我很欣赏这种回应,但......这种方法的问题在于它混合了责任。异步工作流程+“正常”状态。这导致复杂的减速器。在真正的项目中,这意味着您只是更容易创建脆弱的代码。此外,您还没有解决如何实际完成上述工作流程。 –
感谢您的反馈。这是合理的批评。对于最后一点,我相信我主要解决了它的工作原理。那么,因为我今天有一些空闲时间,所以在这里解释了使用减速器布局的一个实例。它有一个'redux-loop'和'redux-sage'实现,几乎完全相同的reducer:[https://github.com/yiransheng/redux-login-examples](https://github.com/yiransheng/redux -login-examples) –
什么是好的是你明确枚举类型的想法。不幸的是,正如他们在美国所说的那样,“你正在击败一匹死马。”另外,对于关注点的混合,您没有专门处理异步性的API。因此,在现实世界的项目中,代码变得非常非常复杂(和重复)。例如,您不处理“取消”情况。其次,FRP /传奇在测试中胜出。你不需要嘲笑。 –