【问题标题】:withLatestFrom does not emit valuewithLatestFrom 不发出值
【发布时间】:2017-11-07 05:35:21
【问题描述】:

我正在尝试阻止主流,直到使用 withLatestFrom 运算符和辅助流(包含有关配置状态的信息)初始化配置。

这是我的代码:

@Effect()
public navigationToActiveRedemptionOffers = this.actions$.ofType(ROUTER_NAVIGATION)
  .filter((action: RouterNavigationAction<RouterStateProjection>) => {
    return action.payload.event.url.includes('/redemption-offers/list/active');
  })
  .do(() => console.log('before withLatestFrom'))
  .withLatestFrom(
    this.store.select(selectConfigInitialized)
      .do(initialized => console.log('before config filter', initialized))
      .filter(initialized => initialized)
      .do(initialized => console.log('after config filter', initialized)),
  )
  .do(() => console.log('after withLatestFrom'))
  .switchMap(data => {
    const action = data[0] as RouterNavigationAction<RouterStateProjection>;

    return [
      new MapListingOptionsAction(action.payload.routerState.queryParams),
      new LoadActiveOffersAction(),
    ];
  });

问题是第二个do(在withLatestFrom之后)块永远不会被调用。 日志:

  • 配置过滤器假之前
  • 在与LatestFrom 之前
  • 在配置过滤器为真之前
  • 配置过滤器为真后

感谢您的建议。

【问题讨论】:

    标签: rxjs


    【解决方案1】:

    我想你想要的是.combineLatest

    withLatestFrom 仅将其前面的内容视为触发器。 combineLatest 将源和提供给它的 observables 都视为触发器。

    所以您的问题是源(路由更改)触发并且传递给withLatest(状态已初始化)的可观察对象由于其过滤器而尚未发出。它仅在源触发后发出一个值。所以它被忽略了。

    这是您正在执行的操作的运行示例:

    const first = Rx.Observable.create((o) => {
      setTimeout(() => {
        o.next();
      }, 2000);
    });
    const second = Rx.Observable.create((o) => {
      setTimeout(() => {
        o.next(false);
      }, 1000);
      setTimeout(() => {
        o.next(true);
      }, 3000);
    });
    
    first
      .do(() => console.log('before withLatestFrom'))
      .withLatestFrom(
        second
          .do(initialized => console.log('before config filter', initialized))
          .filter(initialized => initialized)
          .do(initialized => console.log('after config filter', initialized)),
      )
      .subscribe(() => console.log('after withLatestFrom'));
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"&gt;&lt;/script&gt;

    这里是combineLatest

    const first = Rx.Observable.create((o) => {
      setTimeout(() => {
        o.next();
      }, 2000);
    });
    const second = Rx.Observable.create((o) => {
      setTimeout(() => {
        o.next(false);
      }, 1000);
      setTimeout(() => {
        o.next(true);
      }, 3000);
    });
    
    first
      .do(() => console.log('before withLatestFrom'))
      .combineLatest(
        second
          .do(initialized => console.log('before config filter', initialized))
          .filter(initialized => initialized)
          .do(initialized => console.log('after config filter', initialized)),
      )
      .subscribe(() => console.log('after withLatestFrom'));
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"&gt;&lt;/script&gt;

    【讨论】:

    • 谢谢,combineLatest 操作员工作正常。可能我误解了withLatestFrom docs:“所有输入 Observable 必须至少发出一个值,然后输出 Observable 才会发出一个值。”
    • 只需少量工作,RxJS 的文档就会变得更好。他们需要提供示例用例,而不仅仅涉及一系列发射计时器。我一直在使用 combineLatest 的静态版本一段时间,当 withLatestFrom 什么也没做时我感到非常困惑 - 特别是因为我曾经只使用一个 console.log 命令订阅了那个 observable ,而删除它就是破坏它的原因。
    【解决方案2】:

    withLatestFrom 仅在其源 Observable 发出时才会发出。发生的情况是this.store.select 在源之前发出withLatestFrom。从排放的顺序可以看出:

    • 配置过滤器假之前

    • 在与LatestFrom 之前

    • ...

    现在这取决于您想要实现的目标。只能在源发出时使用concatMap 触发this.store.select(selectConfigInitialized)

    navigationToActiveRedemptionOffers = this.actions$.ofType(ROUTER_NAVIGATION)
      .filter(...)
      .concatMap(() => this.store.select(selectConfigInitialized)...)
      .switchMap(data => { ... })
      ...
    

    或者你可以传递两个 Observable 的结果:

    navigationToActiveRedemptionOffers = this.actions$.ofType(ROUTER_NAVIGATION)
      .filter(...)
      .concatMap(nav => this.store.select(selectConfigInitialized)
        .map(result => [nav, result])
      )
      .switchMap(data => { ... })
      ...
    

    【讨论】:

      【解决方案3】:

      你可以通过反转 observables 来简化它。

      public navigationToActiveRedemptionOffers = 
      
        return this.store.select(selectConfigInitialized)
          .filter(initialized => initialized)      
          .flatMap(x => 
            return this.actions$.ofType(ROUTER_NAVIGATION)
              .filter((action: RouterNavigationAction<RouterStateProjection>) => {
                return action.payload.event.url.includes('/redemption-offers/list/active');
              })
          .map(action =>
            return [
              new MapListingOptionsAction(action.payload.routerState.queryParams),
              new LoadActiveOffersAction(),
            ];
          )
      

      由于这是一种常见的模式,我使用通用的waitFor 方法。

      export const waitFor$ = function() {
        return this.filter(data => !!data ).take(1);
      };
      

      用法,

      return this.config$
        .waitFor$()
        .flatMap(config => {
          return observableWithRequiredValue()
        }
      

      提供的流利语法

      Observable.prototype.waitFor$ = waitFor$;
      
      declare module 'rxjs/Observable' {
        interface Observable<T> {
          waitFor$: typeof waitFor$;
        }
      }
      

      注意,这种创建运算符的方法在 rxjs v5.5 中已被Lettable Operators 取代(但上述方法仍然有效)。

      【讨论】:

        猜你喜欢
        • 2019-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多