调度一个动作来响应取消 [英] Dispatch an action in response to cancellation

查看:43
本文介绍了调度一个动作来响应取消的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从 redux-observable 中的取消配方开始docs 并希望对其进行一些扩展.

I started with the cancellation recipe from the redux-observable docs and want to extend it a bit.

基本上我有一个场景,在触发取消后,使用 takeUntil 我想调度另一个动作来清理等

Basically I have a scenario where after the cancellation is triggered, using takeUntil I want dispatch another action to cleanup, etc.

这是我目前想到的:https://jsbin.com/zemenu/195/edit?js,output

启动获取用户信息",然后点击取消.我希望它按以下顺序执行操作:
- USER/FETCH
- 请求/启动
- 用户/取消
- 请求/取消

Start a "Fetch User Info" and then hit Cancel. I want it to execute actions in this order:
- USER/FETCH
- REQUEST/STARTED
- USER/CANCELLED
- REQUEST/CANCELLED

这以我现在设置的方式工作.但是,我必须依靠将 dispatch 传递到 requestSequence 函数中,然后在 finally 中触发它.是否有一种更简洁的方法可以仅使用可观察的运算符来做到这一点?所以当 USER.CANCELLED 被触发时,一些最终的动作被映射到 requestSequence observable 内部.

This works in the way I have it setup right now. But, I have to rely on passing dispatch into the requestSequence function and then trigger it in finally. Is there a cleaner way to do this just with observable operators? So when that USER.CANCELLED is triggered some final action is mapped to inside the requestSequence observable.

Redux 记录器已启用,因此请检查控制台以了解所有操作.

Redux logger is enabled so check the console for all the actions.

推荐答案

而不是使用 .takeUntil(),听起来您想使用 .race(),这个名字很恰当.无论哪个流首先发出,都赢了!另一个已取消订阅.

Instead of using .takeUntil(), it sounds like you want to use .race(), which is fairly aptly named. Whichever stream emits first, wins! The other is unsubscribed.

您需要稍微重组一些东西才能根据需要使用它.你想隔离你立即发出的第一个动作,你的 request.onStart(meta),与 ajax 请求分开 Observable.fromPromise(apiCall(...args)).然后你想直接在那个 ajax 和取消之间进行比赛,所以你需要传入 action$ ActionsObservable 因为你在一个助手中拥有所有这些.

You'll need to restructure some things a bit to use it as you want. You want to isolate the first action you emit immediately, your request.onStart(meta), separate from the ajax request Observable.fromPromise(apiCall(...args)). Then you want to race directly between that ajax and the cancellation, so you'd need to pass in the action$ ActionsObservable since you have all this in a helper.

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 大师.当然,只有您才能知道此建议是否适用于您和您的代码库.


Side note: be careful about premature abstractions like making those sorts of helpers. Even though you may repeat things in some epics, I've found abstracting it can make it much harder to grok later, especially if it's someone else who didn't write the code and aren't an Rx guru. Only you can know whether this advice applies to you and your codebase, of course.

对我来说,主要的困惑点是您必须传递给 requestSequence 的所有参数,许多人第一次遇到它时很难理解.如果您发现您的史诗非常普遍地做完全相同的事情并且您想要重用,也许抽象整个史诗会更清晰,并创建 API 实用程序,例如下面的 userRequest ,您可以独立测试.

The primary confusing point for me is all the arguments you have to pass to requestSequence, which will be tough for many to understand when they first come across it. If you find that very very commonly your epics do exactly the same thing and you want to reuse, perhaps abstracting the entire epic would be more clear, and create API utilities like userRequest below that you can test independently.

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

(untested, basically pseudo code)

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
});

这篇关于调度一个动作来响应取消的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆