【问题标题】:redux-observable: Mapping to an action as soon as another was triggered at least onceredux-observable:一旦另一个动作被触发至少一次就映射到一个动作
【发布时间】:2017-01-23 12:03:11
【问题描述】:

我有一个 SPA,它正在从服务器加载一些全局/共享数据(我们称之为 APP_LOAD_OK)和特定于页面的数据(DASHBOARD_LOAD_OK)。我想显示加载动画,直到 APP_LOAD_OK 和 DASHBOARD_LOAD_OK 都被调度。

现在我在用 RxJS 表达这一点时遇到了问题。我需要的是在每个 DASHBOARD_LOAD_OK 之后触发一个动作,只要有至少一个 APP_LOAD_OK。像这样的:

action$
  .ofType(DASHBOARD_LOAD_OK)
  .waitUntil(action$.ofType(APP_LOAD_OK).first())
  .mapTo(...)

有人知道,我如何在有效的 RxJS 中表达它?

【问题讨论】:

    标签: rxjs redux-observable


    【解决方案1】:

    您可以使用withLatestFrom,因为它会等到两个源至少发射一次后再发射。如果您使用DASHBOARD_LOAD_OK 作为主要来源:

    action$.ofType(DASHBOARD_LOAD_OK)
      .withLatestFrom(action$.ofType(APP_LOAD_OK) /*Optionally*/.take(1))
      .mapTo(/*...*/);
    

    这允许您在 DASHBOARD_LOAD_OK 多次触发的情况下继续发射。

    【讨论】:

      【解决方案2】:

      我想避免实现一个新的运算符,因为我认为我的 RxJS 知识还不够好,但事实证明它比我想象的要容易。我保持开放,以防有人有更好的解决方案。您可以在下面找到代码。

      Observable.prototype.waitUntil = function(trigger) {
        const source = this;
        let buffer = [];
        let completed = false;
      
        return Observable.create(observer => {
          trigger.subscribe(
            undefined,
            undefined,
            () => {
              buffer.forEach(data => observer.next(data));
              buffer = undefined;
              completed = true;
            });
      
          source.subscribe(
            data => {
              if (completed) {
                observer.next(data);
              } else {
                buffer.push(data);
              }
            },
            observer.error.bind(observer),
            observer.complete.bind(observer)
          );
        });
      };
      

      【讨论】:

      • 您应该注意此实现中的几个危险:a) 您没有清理您创建的订阅 (x2),要成为一名优秀的运营商,您应该返回您的订阅create in create, b) buffercompleted每次调用而不是每次订阅创建的,这是共享状态,对于冷的 Observables 来说不是 bueno(提示尝试多次订阅此流。您可能会看到一些奇怪的行为)。
      • 您说得对,非常感谢您的澄清。 :) 没有考虑太多,我很高兴我终于有了一些解决方案。 (如果我有更多时间,我可能会稍后编辑它,或者如果你愿意,可以自己编辑)
      【解决方案3】:

      如果您想在第一个 APP_LOAD_OK 之后收到每个 DASHBOARD_LOAD_OK 您可以简单地使用skipUntil

      action$ .ofType(DASHBOARD_LOAD_OK)
        .skipUntil(action$.ofType(APP_LOAD_OK).Take(1))
        .mapTo(...)
      

      这只会在第一个 APP_LOAD_OK 之后开始发出 DASHBOARD_LOAD_OK 操作,之前的所有操作都将被忽略。

      【讨论】:

      • 我也考虑过这个解决方案。问题在于,最初(在页面加载时),两个异步“任务”同时启动,因此它们可以按任何顺序完成。这意味着有时加载动画永远不会完成(如果 DASHBOARD_LOAD_OK 先到达)。
      • 如果你只要求它们都发射一次,那么你可以使用Rx.Observable.zip(action$ .ofType(DASHBOARD_LOAD_OK), action$.ofType(APP_LOAD_OK)).take(1).Map/**/)
      猜你喜欢
      • 2017-10-05
      • 1970-01-01
      • 1970-01-01
      • 2020-10-26
      • 2018-11-21
      • 2017-03-18
      • 1970-01-01
      • 2016-10-02
      • 1970-01-01
      相关资源
      最近更新 更多