I have a task to do StopWatch. I did it using Subject, but I should do it via Observables. I read about at rxjs.dev. But I can`t understand it. Help me plz
The stopwatch must have the following buttons:
"Start / Stop" - start / stop timing, stops and resets the stopwatch value.
"Wait" - works on a double click (the time between clicks is not more than 300 ms;) The stopwatch should stop timing, if you press start after it. then the countdown is resumed.
"Reset" - reset the stopwatch to 0. Resets the stopwatch and starts counting again.
import "./App.css";
import { useEffect, useState } from "react";
import { interval, Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
function App() {
const [time, setTime] = useState(0);
const [status, setStatus] = useState(false);
useEffect(() => {
const unsubscribe$ = new Subject();
interval(10)
.pipe(takeUntil(unsubscribe$))
.subscribe(() => {
if (status === true) {
setTime(val => val + 10);
}
});
return () => {
unsubscribe$.next();
unsubscribe$.complete();
};
}, [status]);
const start = React.useCallback(() => {
setStatus(true);
}, []);
const stop = React.useCallback(() => {
setStatus(false);
}, []);
const reset = React.useCallback(() => {
setTime(0);
setStatus(false);
}, []);
console.log(time);
return (
<div className="App">
<h1>Секундомер</h1>
<span>{Math.floor(time / (1000 * 60 * 60)) % 24}</span>
<span>{Math.floor((time / (1000 * 60)) % 60)}</span>
<span>{Math.floor((time / 1000) % 60)}</span>
<div>
<button onClick={()=> start()} class="start">Старт</button>
<button onClick={()=> stop()}class="stop">Стоп</button>
<button onClick={()=> reset()} class="reset">Перезапуск</button>
</div>
</div>
);
}
export default App;```
I created a pretty generic stopwatch implementation a while back.
type StopwatchAction = "START" | "STOP" | "RESET" | "END";
function createStopwatch(
control$: Observable<StopwatchAction>,
interval = 1000
): Observable<number>{
return defer(() => {
let toggle: boolean = false;
let count: number = 0;
const ticker = timer(0, interval).pipe(
map(x => count++)
);
const end$ = of("END");
return concat(
control$,
end$
).pipe(
catchError(_ => end$),
switchMap(control => {
if(control === "START" && !toggle){
toggle = true;
return ticker;
}else if(control === "STOP" && toggle){
toggle = false;
return EMPTY;
}else if(control === "RESET"){
count = 0;
if(toggle){
return ticker;
}
}
return EMPTY;
})
);
});
}
Using this is just a matter of hooking the correct events into a stream of StopwatchAction
s. This example only sends "START"
and "RESET"
based on button clicks, but you can merge in "STOP"
and "END"
as well.
For example:
createStopwatch(merge(
fromEvent(startBtn, 'click').pipe(mapTo("START")),
fromEvent(resetBtn, 'click').pipe(mapTo("RESET"))
)).subscribe(seconds => {
secondsField.innerHTML = seconds % 60;
minuitesField.innerHTML = Math.floor(seconds / 60) % 60;
hoursField.innerHTML = Math.floor(seconds / 3600);
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.