RxJS - 使计数器重置为无状态? [英] RxJS - make counter with reset stateless?
问题描述
假设我有以下标记:
<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 .startWith
s 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屋!