Tengo una tarea para hacer StopWatch. Lo hice usando Asunto, pero debería hacerlo a través de Observables. Leí sobre en rxjs.dev. Pero no puedo entenderlo. ayúdame por favor
El cronómetro debe tener los siguientes botones:
"Start/Stop": inicia/detiene el tiempo, detiene y restablece el valor del cronómetro.
"Esperar": funciona con un doble clic (¡el tiempo entre clics no es más de 300 ms!) El cronómetro debe detener el tiempo; si presiona iniciar después, se reanuda la cuenta regresiva.
"Restablecer": restablece el cronómetro a 0. Restablece el cronómetro y comienza a contar nuevamente.
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;```Creé una implementación de cronómetro bastante genérica hace un tiempo.
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; }) ); }); } Usar esto es solo una cuestión de conectar los eventos correctos en una secuencia de StopwatchAction s. Este ejemplo solo envía "START" y "RESET" en función de los clics del botón, pero también puede combinar "STOP" y "END" .
Por ejemplo:
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); });