Rxjs 如何创建一个从ngrx选择器发出一个值,然后在延迟后再发出另一个值的可观察对象?

Rxjs 如何创建一个从ngrx选择器发出一个值,然后在延迟后再发出另一个值的可观察对象?,rxjs,ngrx,Rxjs,Ngrx,给定ngrx选择器: store.select('count') 我想创建一个observable,它将发出选择器发出的值,然后在延迟后发出另一个特定值 使用concat不起作用,因为(我假设)选择器没有完成,因此永远不会发出0: this.count$ = concat(store.select('count'), of(0).pipe(delay(2000))); 闪电战: -单击“增量”按钮-当前计数应更改为1,然后在2秒后返回0。下面是使用combinelatetest和Behavi

给定ngrx选择器:

store.select('count')
我想创建一个observable,它将发出选择器发出的值,然后在延迟后发出另一个特定值

使用
concat
不起作用,因为(我假设)选择器没有完成,因此永远不会发出0:

this.count$ = concat(store.select('count'), of(0).pipe(delay(2000)));
闪电战:
-单击“增量”按钮-当前计数应更改为1,然后在2秒后返回0。

下面是使用
combinelatetest
BehaviorSubject

我们将在一个主题中保存一个值,并创建一个计时器,该计时器在2s后发出值0。所以我们有两个观测值,一个立即发射,另一个在2秒后发射。我们将这两者结合起来,效果是一个单一的可观察到的

  valueHolderSubject$ = new BehaviorSubject(0);

  ...

    this.count$ = combineLatest([
      store.select("count").pipe(
        tap(x => this.valueHolderSubject$.next(x)),
        tap(() =>
          timer(2000).subscribe({
            next: () => {
              this.valueHolderSubject$.next(0);
            }
          })
        ),
        map(() => this.valueHolderSubject$.value),
        distinctUntilChanged()
      ),
      this.valueHolderSubject$
    ]).pipe(map(([, x]) => x));

下面是一种使用
组合测试
行为主体

我们将在一个主题中保存一个值,并创建一个计时器,该计时器在2s后发出值0。所以我们有两个观测值,一个立即发射,另一个在2秒后发射。我们将这两者结合起来,效果是一个单一的可观察到的

  valueHolderSubject$ = new BehaviorSubject(0);

  ...

    this.count$ = combineLatest([
      store.select("count").pipe(
        tap(x => this.valueHolderSubject$.next(x)),
        tap(() =>
          timer(2000).subscribe({
            next: () => {
              this.valueHolderSubject$.next(0);
            }
          })
        ),
        map(() => this.valueHolderSubject$.value),
        distinctUntilChanged()
      ),
      this.valueHolderSubject$
    ]).pipe(map(([, x]) => x));

如果要发射
存储。选择('count')
值,然后在2秒钟内未接收到发射后将其重置为
0
,可以使用创建发射两个值的源:

  • 发出的
    计数
  • 2000ms后
    0
    的“默认”值
  • 这里的技巧是,如果接收到另一个
    存储,则不会发出第二个值(
    0
    )。选择('count')
    值,因为
    switchMap
    将创建一个新源并“切换”到该值:

    this.count$=store.select('count').pipe(
    开关映射(计数=>concat(
    共(个),
    of(0).管道(延迟(2000))
    ))
    );
    
    这是一个工作演示


    甚至可能值得创建一个自定义操作符:

    this.count$=this.store.select('count').pipe(
    重置后延迟(0,2000)
    );  
    
    导出函数resetAfterDelay(默认值:T,delayMs:number){
    返回switchMap((值:T)=>concat(
    价值的,
    of(默认值)。管道(延迟(延迟毫秒))
    ));
    }
    

    如果要发射
    存储。选择('count')
    值,然后在2秒钟内未接收到发射后将其重置为
    0
    ,可以使用创建发射两个值的源:

  • 发出的
    计数
  • 2000ms后
    0
    的“默认”值
  • 这里的技巧是,如果接收到另一个
    存储,则不会发出第二个值(
    0
    )。选择('count')
    值,因为
    switchMap
    将创建一个新源并“切换”到该值:

    this.count$=store.select('count').pipe(
    开关映射(计数=>concat(
    共(个),
    of(0).管道(延迟(2000))
    ))
    );
    
    这是一个工作演示


    甚至可能值得创建一个自定义操作符:

    this.count$=this.store.select('count').pipe(
    重置后延迟(0,2000)
    );  
    
    导出函数resetAfterDelay(默认值:T,delayMs:number){
    返回switchMap((值:T)=>concat(
    价值的,
    of(默认值)。管道(延迟(延迟毫秒))
    ));
    }
    

    根据我对BizzyBob答案的评论,我得到的结果不可靠。但我使用以下方法对其进行了改进:

    this.count$ = merge(
          store.select('count'), 
          store.select('count').pipe(delay(2000), map(_ => 0))
    );
    

    参见stackblitz:

    根据我对BizzyBob答案的评论,我得到的结果不可靠。但我使用以下方法对其进行了改进:

    this.count$ = merge(
          store.select('count'), 
          store.select('count').pipe(delay(2000), map(_ => 0))
    );
    

    请参阅stackblitz:

    我想要一个如此简单的解决方案,但我无法让这两个方案都可靠地工作,而且它们在第一次发射后似乎从未工作过。请参见此处修改示例中的my-counter.component.ts:我不确定“可靠工作”是什么意思?我已将控制台日志添加到您的SB示例中,它们似乎都非常有效:|哦,我看到了您的解决方案和您真正想要的。您希望
    0
    在每次
    store发出后2秒发出。选择('count')
    。我没有意识到这一点。我想要一个这样简单的解决方案,但我不能让这两个都可靠地工作,而且它们在第一次发射后似乎永远不会工作。请参见此处修改示例中的my-counter.component.ts:我不确定“可靠工作”是什么意思?我已将控制台日志添加到您的SB示例中,它们似乎都非常有效:|哦,我看到了您的解决方案和您真正想要的。您希望
    0
    在每次
    store发出后2秒发出。选择('count')
    。我没有意识到这一点。感谢这一点,虽然它起作用了,但我还是选择了一个更简单的解决方案,就像我发布的答案一样。感谢这一点,虽然它起作用了,但我选择了一个更简单的解决方案,就像我发布的答案一样。这个解决方案的一个潜在问题是,每次发射后,你总是会发射
    0
    2000ms。如果在2秒内发出多个
    count
    值,则
    0
    值将在2秒内清除新收到的值。请参阅我的更新答案,以了解防止这种情况发生的解决方案。是的,这是一个好问题。我没有深入思考这种情况下的行为。此解决方案的一个潜在问题是,每次发射后,您将始终发射
    0
    2000ms。如果在2秒内发出多个
    count
    值,则
    0
    值将在2秒内清除新收到的值。请参阅我的更新答案,以获得防止这种情况发生的解决方案。是的,这是一个好问题,我对这种情况下的行为没有深入思考。