2016-12-08 62 views
3

我从012x开始使用可重复观察的文档,并希望对其进行扩展。发送取消操作

基本上我有该项取消被触发后的场景,使用takeUntil我想派遣另一个动作进行清理等

这是我想出了迄今:https://jsbin.com/zemenu/195/edit?js,output

开始了“获取用户信息“,然后点击取消。我希望它在这个顺序执行操作:
- USER/FETCH
- REQUEST/STARTED
- USER/CANCELLED
- REQUEST/CANCELLED

这工作的方式我现在有它的设置。但是,我必须依靠将dispatch传入requestSequence函数,然后在finally中触发它。有没有更清晰的方法来完成这一点,只需要可观察的操作员?所以当USER.CANCELLED被触发时,一些最终动作被映射到requestSequence可观察值内。

Redux记录器已启用,因此请检查控制台的所有操作。

回答

6

而不是使用.takeUntil(),它听起来像你想使用.race(),这是相当合适的命名。无论哪条小溪首先发射,胜利!另一个是取消订阅。

你需要重新调整一些东西来使用它,只要你想。您希望将您立即发出的第一个动作(request.onStart(meta))与ajax请求Observable.fromPromise(apiCall(...args))分开。然后你想直接在ajax和取消之间进行比赛,所以你需要传递action$ ActionsObservable,因为你已经把所有这些都放在了辅助函数中。

https://jsbin.com/suvaka/edit?js,output

function requestSequence(apiCall, args, meta, action$) { 
    return Observable.of(request.onStart(meta)) 
    .concat(
     Observable.fromPromise(apiCall(...args)) 
     .map((payload) => request.onSuccess(payload, meta)) 
     .catch((e) => Observable.of(request.onError(e, meta))) 
     .race(
      action$.ofType(USER.CANCELLED) 
      .map(() => request.onCancel(meta)) 
     ) 
    ); 
} 

const fetchUserEpic = (action$, store) => 
    action$.ofType(USER.FETCH) 
    .mergeMap(action => 
     requestSequence(
     userRequest, 
     [`/api/users/${action.payload}`], 
     { activity: USER.FETCH, path: 'user' }, 
     action$ 
    ) 
    ); 

边注:小心过早抽象,如让那些五花八门的助手。尽管你可能会在某些史诗中重复一些事情,但我发现抽象它可能会使得以后更难以发现,特别是如果它是别人不写代码而不是Rx大师的话。当然,只有您可以知道这个建议是否适用于您和您的代码库。

对我来说,主要的困惑点是你必须传递给requestSequence的所有论点,这对许多人来说首先遇到它是很难理解的。如果你发现非常常见的你的史诗般做了完全相同的事情并且你想要重复使用,也许抽象整个史诗将更加清晰,并创建下面的API工具,例如userRequest,你可以独立测试。

(未经测试,基本上是伪代码)

const createApiEpic = options => 
    action$ => 
    action$.ofType(options.on) 
     .mergeMap(action => 
     Observable.of(request.onStart(meta)) 
      .concat(
      options.effect(action.payload) 
       .map(payload => request.onSuccess(payload, meta)) 
       .catch(e => Observable.of(request.onError(e, meta))) 
       .race(
       action$.ofType(options.cancel) 
        .map(() => request.onCancel(meta)) 
      ) 
     ) 
    ); 

const userRequest = id => 
    Observable.ajax.getJSON(`/api/users/${id}`); 

const fetchUserEpic = createApiEpic({ 
    on: USER.FETCH, 
    effect: userRequest 
    cancel: USER.CANCELLED 
}); 
+0

感谢真棒解释! 'createApiEpic'方法似乎更加清洁。 – winkerVSbecks

+0

@winkerVSbecks欢迎您! – jayphelps