@@ -374,3 +374,58 @@ function App() {
374
374
const rootElement = document.getElementById("root");
375
375
ReactDOM.render(<App />, rootElement);
376
376
` ` `
377
+
378
+ ** Example of combining callback observables coming from separate elements - animation with start / stop button and rate controllable via slider **
379
+
380
+ [live demo ](https :// codesandbox.io/s/pprzmxy230)
381
+
382
+ ` ` ` tsx
383
+ const Animation = ({ frame }) => {
384
+ const frames = "|/-\\ |/-\\ |".split("");
385
+ return (
386
+ <div>
387
+ <p>{frames[frame % frames.length]}</p>
388
+ </div>
389
+ );
390
+ };
391
+
392
+
393
+ const App = () => {
394
+ const defaultRate = 5;
395
+
396
+ const [running, setRunning] = useState(false);
397
+
398
+ const [onEvent, frame] = useEventCallback(events$ => {
399
+ const running$ = events$.pipe(
400
+ filter(e => e.type === "click"),
401
+ scan(running => !running, running),
402
+ startWith(running),
403
+ tap(setRunning)
404
+ );
405
+
406
+ return events$.pipe(
407
+ filter(e => e.type === "change"),
408
+ map(e => parseInt(e.target.value, 10)),
409
+ startWith(defaultRate),
410
+ switchMap(i => timer(200, 1000 / i)),
411
+ withLatestFrom(running$),
412
+ filter(([_, running]) => running),
413
+ scan(frame => frame + 1, 0)
414
+ );
415
+ });
416
+
417
+ return (
418
+ <div className="App">
419
+ <button onClick={onEvent}>{running ? "Stop" : "Start"}</button>
420
+ <input
421
+ type="range"
422
+ onChange={onEvent}
423
+ defaultValue={defaultRate}
424
+ min="1"
425
+ max="10"
426
+ ></input>
427
+ <Animation frame={frame} />
428
+ </div>
429
+ );
430
+ };
431
+ ` ` `
0 commit comments