RxJS - 使计数器重置为无状态? [英] RxJS - make counter with reset stateless?

查看:19
本文介绍了RxJS - 使计数器重置为无状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下标记:

<button id="dec">-</button>
<output id="out">0</output>
<button id="inc">+</button>
<button id="res">RESET</button>

以及以下 Rx.js 脚本:

And the following Rx.js script:

var total = 0

Rx.Observable.merge(
    // decrement
    Rx.Observable.fromEvent($('#dec'), 'click')
    .map(function() { return -1 }),

    // increment
    Rx.Observable.fromEvent($('#inc'), 'click')
    .map(function() { return +1 }),

    // reset
    Rx.Observable.fromEvent($('#res'), 'click')
    .map(function() { return -total })
) // merge
.forEach(function(delta) {
    total += delta
    $('#out').text(total)
})

一切都按预期进行.单击 +/- 增加/减少计数器,然后单击RESET"将其重置为零,但是...我在顶部有变量total".这是状态,如果我订阅函数式反应式编程的价值,它是邪恶的,不是吗?如果是这样,我该如何补救?如果我没有重置按钮,我可以只使用 scan(seed, accumulator),但是重置按钮的功能让我陷入循环,至于如何做到无状态"'.

Everything works as expected. Clicking the +/- increments/decrements the counter, and clicking 'RESET' resets it back to zero, but...I have the variable 'total' at the top. This is state, which if I subscribe to the values of functional reactive programming, is evil, no? If so, how do I remedy this? If I didn't have the reset button, I could just use scan(seed, accumulator), but the functionality of the reset button is throwing me for a loop, as to how to do it 'stateless'.

在这里工作.

推荐答案

我可以看到有两种方法可以解决这个问题.

There are two ways of going about this that I can see.

首先,没有什么说你不能在管道中扩充你的数据:

First, there is nothing that says you can't augment your data in the pipeline:

Rx.Observable.merge(
  // decrement
  Rx.Observable.fromEvent($('#dec'), 'click')
    .map(function() { return {delta : -1}; }),

  // increment
  Rx.Observable.fromEvent($('#inc'), 'click')
    .map(function() { return {delta : +1}; }),

  // reset
  Rx.Observable.fromEvent($('#res'), 'click')
    .map(function() { return {reset : true}; })
) // merge
.scan(0, function(acc, value) {
  return value.reset ? 0 : acc + value.delta;
})
.forEach(function(delta) {
  $('#out').text(delta)
});

以上让您可以通过添加字段向下游发出信号表示流已重置(注意:我作弊了,为了可读性,您可能想要添加 reset : false 而不是依赖于 falsey-ness,但这取决于您).

The above lets you signal downstream that the stream has been reset by adding in a field (note: I cheated, for readability you might want to add reset : false rather than rely on falsey-ness, but it's up to you).

或者,如果您认为 reset 实际上是在重置流,那么您可以改用 flatMapLatest 来包装递增和递减:

Alternatively, if you think of the reset as actually resetting the stream then you could instead use flatMapLatest to wrap the incrementing and decrementing:

Rx.Observable.fromEvent($('#res'), 'click')
.startWith(null)
.flatMapLatest(function(e) {
  return Rx.Observable.merge(
    // decrement
    Rx.Observable.fromEvent($('#dec'), 'click')
      .map(function() { return -1 }),

    // increment
    Rx.Observable.fromEvent($('#inc'), 'click')
      .map(function() { return +1 })
  )
  .scan(0, function(acc, delta) { return acc + delta })
  .startWith(0);
})
.subscribe(function(value) {
   $('#out').text(value) 
});

这使得流比包含两个 .startWith 以启动相应序列的流变得更加混乱,但是如果您反对增加并希望隐式状态由流控制,那么这将是一种方法.

This makes the stream a little bit messier than it has to be with the inclusion of two .startWiths to kick off the respective sequences, but if you were opposed to augmenting and wanted the state implicitly controlled by the stream then this would be an approach.

这篇关于RxJS - 使计数器重置为无状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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