@@ -374,3 +374,58 @@ function App() {
374374const rootElement = document.getElementById("root");
375375ReactDOM.render(<App />, rootElement);
376376` ` `
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