Refactoring streams in RxJS is mostly moving pieces of smaller streams around. This lessons demonstrates a simple refactoring by requiring the StopWatch to be more configurable.
Code we have now:
const Observable = Rx.Observable; const startButton = document.querySelector('#start'); const stopButton = document.querySelector('#stop'); const resetButton = document.querySelector('#reset'); const start$ = Observable.fromEvent(startButton, 'click'); const interval$ = Observable.interval(1000); const stop$ = Observable.fromEvent(stopButton, 'click'); const reset$ = Observable.fromEvent(resetButton, 'click'); const data = {count:0}; const inc = (acc)=> ({count: acc.count + 1}); const reset = (acc)=> data; const intervalThatStops$ = interval$ .takeUntil(stop$); const incOrReset$ = Observable.merge( intervalThatStops$.mapTo(inc), reset$.mapTo(reset) ); start$ .switchMapTo(incOrReset$) .startWith(data) .scan((acc, curr)=> curr(acc)) .subscribe((x)=> console.log(x));
Currently the interval is hard code 1000, we want it more flexable:
const Observable = Rx.Observable; const startButton = document.querySelector('#start'); const halfButton = document.querySelector('#half'); const quarterButton = document.querySelector('#quarter'); const stopButton = document.querySelector('#stop'); const resetButton = document.querySelector('#reset'); const start$ = Observable.fromEvent(startButton, 'click'); const half$ = Observable.fromEvent(halfButton, 'click'); const quarter$ = Observable.fromEvent(quarterButton, 'click'); const stop$ = Observable.fromEvent(stopButton, 'click'); const reset$ = Observable.fromEvent(resetButton, 'click');
We added two more buttons, halfButton set interval as 500, and quarterButton is 250.
So when we click "start", "half" or "quarter" button, the interval will set differently.
Observable.merge( start$.mapTo(1000), half$.mapTo(500), quarter$.mapTo(250) )
We want pass the time (1000, 500, 250) to the next observable to control the time.
Observable.merge( start$.mapTo(1000), half$.mapTo(500), quarter$.mapTo(250) ) .switchMap( (time) => { return Observable.merge( Observable.interval(time) .takeUntil(stop$) .mapTo(inc), reset$.mapTo(reset) ) } )
We use switchMap() instead of switchMapTo() is becuase switchMapTo() accept observable as param and switchMap accpet a function which return an Observable. So use switchMap() is more flexable.
-------------
const Observable = Rx.Observable; const startButton = document.querySelector('#start'); const halfButton = document.querySelector('#half'); const quarterButton = document.querySelector('#quarter'); const stopButton = document.querySelector('#stop'); const resetButton = document.querySelector('#reset'); const start$ = Observable.fromEvent(startButton, 'click'); const half$ = Observable.fromEvent(halfButton, 'click'); const quarter$ = Observable.fromEvent(quarterButton, 'click'); const stop$ = Observable.fromEvent(stopButton, 'click'); const reset$ = Observable.fromEvent(resetButton, 'click'); const data = {count:0}; const inc = (acc)=> ({count: acc.count + 1}); const reset = (acc)=> data; Observable.merge( start$.mapTo(1000), half$.mapTo(500), quarter$.mapTo(250) ) .switchMap( (time) => { return Observable.merge( Observable.interval(time) .takeUntil(stop$) .mapTo(inc), reset$.mapTo(reset) ) } ) .startWith(data) .scan( (acc, curr) => curr(acc)) .subscribe( (z) => console.log(z) );