Estoy tratando de crear un temporizador con React Hook para usarlo en un contexto. No tengo ningún problema cuando lo ejecuto usando Context y Vanilla JS, pero cuando uso Hooks parece estar unos milisegundos atrás.
Mi useTimerHook:
import { useState } from 'react'; const useTimerHook = () => { const [minutes, setMinutes] = useState(0); const [seconds, setSeconds] = useState(0); const [miliSeconds, setMiliSeconds] = useState(0); function write() { let mt, st, mlst; setMiliSeconds(miliSeconds + 1); if (miliSeconds > 99) { setSeconds(seconds + 1); setMiliSeconds(0); } if (seconds > 59) { setMinutes(minutes + 1); setSeconds(0); } mlst = ('0' + miliSeconds).slice(-2); st = ('0' + seconds).slice(-2); mt = ('0' + minutes).slice(-2); return `${mt}:${st}:${mlst}`; } function reset() { setMinutes(0); setMiliSeconds(0); setSeconds(0); } return { write, reset, }; };Mi contexto:
import useTimerHook from '@hooks/useTimerHook'; const FightContext = createContext(); function FightProvider(props) { const [time, setTime] = useState('Presiona Start'); const [status, setStatus] = useState(false); const { write: write, reset: reset } = useTimerHook(); const startFight = () => { setStatus(true); }; const endFight = () => { setStatus(false); reset(); }; useEffect(() => { if (status) { const timer = setTimeout(() => setTime(write()), 10); return () => { clearTimeout(timer); }; } }); return ( <FightContext.Provider value={{ time, startFight, endFight, status, }} > {props.children} </FightContext.Provider> ); } export { FightContext, FightProvider };Como dije, cuando intento ejecutar esto, el temporizador es más lento de lo que debería ser. Es decir, cuando el temporizador de mi teléfono está en 15 segundos, el temporizador Hook está en 13.
Estoy bastante seguro de que me estoy perdiendo algo obvio aquí, o tal vez no entiendo completamente cómo funcionan Hooks and Context.
En lugar de mantener el "valor del temporizador" en el estado, ¿por qué no confiar simplemente en el tiempo del dispositivo y aplicar las reglas de compensación? Sugiero mantener las marcas de tiempo de inicio y finalización en el estado y luego simplemente calcular la diferencia. Piense en ello como marcar puntos en una cinta métrica y luego calcular la diferencia. De esa manera, problemas como los tiempos de cuadro no afectarán el valor de su temporizador.
Para mostrar el reloj "en ejecución", puede usar setInterval() , por ejemplo, cada segundo o incluso más rápido y luego mostrar la diferencia entre la marca de tiempo de inicio y la marca de tiempo para now() .
Para tener la capacidad de pausar y reanudar el temporizador, mantendría una matriz de objetos de la forma:
// example: // [ // {value: 0, type: "start"}, // {value: 1000, type: "stop"}, // {value: 5000, type: "start"}, // ] const [timeStamps, setTimestamps] = useState([]);Para agregar una nueva marca de tiempo al estado:
const nextStampType = timeStamps.length > 0 ? timeStamps[timeStamps.length - 1].type === "start" ? "stop" : "start" : "start"; setTimeStamps([...timestamps, {value: Date.now(), type: nextStampType} Luego puede usar una función de utilidad que recorre la matriz para calcular el valor del temporizador. Dependiendo de su caso de uso, puede compartir el valor del temporizador o la matriz de timeStamps de tiempo a través de React Context.