2017-02-21 65 views
2

是否有任何使用redux-loop来处理复杂的ajax工作流的例子?官方回购非常简约。从我能找到的一个例子(https://hackernoon.com/why-i-wrote-a-redux-async-outerware-277d450dba74#.2ocaloc58)看来,redux-loop与redux-thunk非常相似。复杂的redux循环示例?

这里有复杂的Ajax的工作流程的一些例子:

  • 阿贾克斯Workflow1。用户在结果表上选择两个不同的过滤器。每个过滤器都会启动一个ajax请求,然后按顺序排除。结果表格应显示正确的过滤器选择。错误不应该更新结果表。
  • Ajax的工作流程2
    • 用户启动一个报告生成(这是一种长时间运行的过程)。
    • 用户切换到另一个报告。它应该取消或忽略待处理的“等待报告”操作。
  • 更复杂的工作流(基于旧终极版-佐贺示例)
    • 用户按下登录按钮,它启动一个AJAX请求来获取令牌一个auth
    • 要么
      • 用户立即按下注销按钮,该按钮应该取消/忽略挂起的认证动作
      • 或者它应该在解析时存储认证令牌
    • 应该退出后清除身份验证令牌或出现登录错误

回答

2

我会给在第二个工作流(登录)一杆。

在进入代码之前,值得注意的是redux-loop比异步控制流程简单很多,并且提供了小于redux-saga。但本着Elm的精神,重点在于数据流 - 通常通过数据类型来实现这一点并不令人意外。因此,从静态类型语言的角度思考是有帮助的。在HaskellElm,这可能有利于模型的数据类型,其本身编码状态机的问题:

data LoginStatus data err = 
    LoggedOut  | 
    , LoggedIn data | 
    , LoginError err | 
    , Pending 

dataerr是类型变量代表登录的数据类型(标记)和登录错误。 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

+0

我很欣赏这种回应,但......这种方法的问题在于它混合了责任。异步工作流程+“正常”状态。这导致复杂的减速器。在真正的项目中,这意味着您只是更容易创建脆弱的代码。此外,您还没有解决如何实际完成上述工作流程。 –

+0

感谢您的反馈。这是合理的批评。对于最后一点,我相信我主要解决了它的工作原理。那么,因为我今天有一些空闲时间,所以在这里解释了使用减速器布局的一个实例。它有一个'redux-loop'和'redux-sage'实现,几乎完全相同的reducer:[https://github.com/yiransheng/redux-login-examples](https://github.com/yiransheng/redux -login-examples) –

+0

什么是好的是你明确枚举类型的想法。不幸的是,正如他们在美国所说的那样,“你正在击败一匹死马。”另外,对于关注点的混合,您没有专门处理异步性的API。因此,在现实世界的项目中,代码变得非常非常复杂(和重复)。例如,您不处理“取消”情况。其次,FRP /传奇在测试中胜出。你不需要嘲笑。 –