2015-07-15 17 views
7

मान लिया जाये कि मैं निम्न मार्कअप है:आरएक्सजेएस - रीसेट स्टेटलेस के साथ काउंटर बनाओ?

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

और निम्नलिखित Rx.js स्क्रिप्ट:

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' पर क्लिक करके इसे शून्य पर वापस रीसेट कर दिया जाता है, लेकिन ... मेरे पास शीर्ष पर चर 'कुल' है। यह राज्य है, जो कि अगर मैं कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग के मूल्यों की सदस्यता लेता हूं, तो बुराई है, नहीं? यदि हां, तो मैं इसका समाधान कैसे करूं? अगर मेरे पास रीसेट बटन नहीं था, तो मैं केवल scan(seed, accumulator) का उपयोग कर सकता था, लेकिन रीसेट बटन की कार्यक्षमता मुझे लूप के लिए फेंक रही है, ताकि यह 'स्टेटलेस' कैसे किया जा सके।

Working fiddle here

उत्तर

14

इस बारे में जाने के दो तरीके हैं जिन्हें मैं देख सकता हूं।

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 जोड़ना चाहेंगे, लेकिन यह आपके ऊपर है)।

वैकल्पिक रूप से, अगर आप reset के बारे में सोच के रूप में वास्तव में धारा को रीसेट तो आपको इसके flatMapLatest इस्तेमाल कर सकते हैं incrementing और 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 एस को शामिल करने के साथ, लेकिन यदि आप बढ़ने का विरोध कर रहे थे और चाहते थे कि राज्य पूरी तरह से धारा द्वारा नियंत्रित हो, तो यह एक दृष्टिकोण होगा।

+0

मुझे लगता है कि पहला विकल्प पढ़ने के लिए सबसे आसान है। दूसरा एक बहुत चालाक है, जवाब देने के लिए समय लेने के लिए धन्यवाद! – Jrop

0

@Jrop मुझे यह ऑपरेटर Rx.Observable.when पसंद है। इस के साथ आप Bacon.update को पुन: पेश कर सकते हैं।

const {when, fromEvent} = Rx.Observable; 

const decObs = fromEvent(document.getElementById('dec'), 'click'); 
const incObs = fromEvent(document.getElementById('inc'), 'click'); 
const resetObs = fromEvent(document.getElementById('res'), 'click'); 

when(
    decObs.thenDo(_ => prev => prev - 1), 
    incObs.thenDo(_ => prev => prev + 1), 
    resetObs.thenDo(_ => prev => 0) 
).startWith(0).scan((prev, f) => f(prev)) 
.subscribe(v => document.getElementById('out').innerHTML = v); 

अगर आप इस Join-calculus, New Release and Joins को देखो और इस Combining sequences

7

बाद @paulpdaniels का जवाब भी बेहतर होगा, यहाँ है क्या मैं Ramda साथ उपयोग कर रहा हूँ:

यह मेरा कोड और jsbin उदाहरण है
var hardSet = Rx.Observable.fromEvent($('#set'); 
var decRes = Rx.Observable.fromEvent($('#dec'); 
var incRes = Rx.Observable.fromEvent($('#inc'); 

Rx.Observable.merge(
    incRes.map(function() { return R.add(1); }), 
    decRes.map(function() { return R.add(-1); }), 
    hardSet.map(function() { return R.always(0); }) 
).scan(function(prev, f) { 
    return f(prev); 
}, 0); 
संबंधित मुद्दे