Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

98
Visualizações
Retraso inestable useEffect de React

Estoy trabajando en un reloj Pomodoro. Para construir las cuentas regresivas, estoy usando useEffect y setTimeout. Todo parecía estar bien hasta que me di cuenta de que hay un retraso de 30ms a 50ms entre cada segundo del reloj. ¿Cómo lo configuraría para que actualice el reloj de manera costosa cada 1000 ms?

Estoy usando useState para manejar la hora del reloj y los controles para detener, pausar y restablecer. Todos están funcionando correctamente. Es solo el momento del segundo el que se está retrasando más de lo que debería.

 function App() { const [workTarget, setWorkTarget] = useState(25 * 60); const [breakTarget, setBreakTarget] = useState(5 * 60); const [time, setTime] = useState(workTarget); //time in seconds const [counting, setCounting] = useState(false); const [working, setWorking] = useState(true); const [clockTarget, setClockTarget] = useState(workTarget); const [combo, setCombo] = useState(0); const [config, setConfig] = useState(false); const [playWork] = useSound(workSfx); const [playBreak] = useSound(breakSfx); const [playPause] = useSound(pauseSfx); let tick = 1000; let timeout; let timenow = Date.now(); // Handle pause and stop of countdown useEffect(() => { if (time > 0 && counting === true) { timeout = setTimeout(() => { setTime(time - 1); console.log(timenow); }, tick); } else if (time === 0 && counting === true) { setWorking(!working); if (working === true) { playBreak(); setTime(breakTarget); setClockTarget(breakTarget); } else { playWork(); setCombo(combo + 1); setTime(workTarget); setClockTarget(workTarget); } } if (!counting || config) { clearTimeout(timeout); } }); } export default App;

Este no es el código completo. Corté otros componentes para botones y cosas que no se relacionan con esto.

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

No podemos asegurar que sea EXACTAMENTE 1000 ms. Detrás de escena, las actualizaciones de estado de reacción usan setTimeout , y para cambiar el temporizador, debe usar setTimeout o setInterval . setTimeout y setInterval solo garantizan que el código interno no se ejecutará durante un período de retraso y luego se ejecuta cuando el subproceso principal no está ocupado .

Por lo tanto, es imposible garantizar que cada actualización sea EXACTAMENTE de 1000 ms. Por lo general, habrá un retraso de 30 a 50 ms.

Sin embargo, eso no significa que su temporizador será inexacto o poco confiable. Solo depende de cómo lo inicialices.

A continuación se muestra cómo mejoraría el código que proporcionó, ya que en este momento borrar el tiempo de espera agrega una sobrecarga adicional, y el procesamiento por lotes de las actualizaciones de estado conduciría a un mejor rendimiento en este caso.

 let tick = 1000; //countdown modifying behavior every 1000ms. Active clock useEffect(() => { if (time > 0 && counting === true) { setTimeout(() => { setTime((state) => state - 1); console.log(timenow); }, tick); } }, [time, counting]); //pausing, stopping and resuming useEffect(() => { if (time === 0 && counting === true) { setWorking(!working); if (working === true) { playBreak(); unstable_batchedUpdates(() =>{ setTime(breakTarget); setClockTarget(breakTarget); } } else { playWork(); //update all at once unstable_batchedUpdates(() =>{ setCombo(combo + 1); setTime(workTarget); setClockTarget(workTarget); } } } }, [time, counting]);

Más mejoras para mantener el reloj sincronizado

  1. En el montaje del componente, tome la hora actual para la hora de inicio , calcule la hora de finalización y almacene ambas
  2. En cada setTimeout en su useEffect , utilizando su hora de inicio almacenada y la hora actual, calcule cuánto tiempo queda y establezca el estado en eso.
 //countdown time modifying behavior every 1000ms const current = new Date() const [start, setStart] = useState(current) //this example uses a 25 minute timer as an example const [end, setEnd] = useState(new Date(start.getTime() + 25 * 60000)) const tick = 1000 useEffect(() => { if (time > 0 && counting === true) { setTimeout(() => { const current = new Date() const diffTime = current.getDate() - end.getDate() const timeRemainingInMins = Math.ceil(diffTime / (1000*60)); setTime(timeRemainingInMins); }, tick); } }, [time, counting]);
about 4 years ago · Juan Pablo Isaza Relatório

0

Puedo tener una idea.

Actualmente, su gancho useEffect está configurado para ejecutarse en cada renderizado, lo que significa que cada vez que cambia la Hora en que renderiza la página y vuelve a ejecutar el gancho useEffect, sin embargo, parece tener bastante lógica dentro del gancho, además, es posible que la reacción no se muestre de manera consistente. lo que significa que puede haber algunas inconsistencias con su tiempo.

Sugiero usar setInterval en su lugar y ejecutar el enlace useEffect solo una vez al principio para configurar el intervalo usando useEffect(() => {...}, []) (observe [] como el segundo argumento)

Para el resto de su lógica, siempre puede crear otro enlace useEffect que se actualice cuando cambien los componentes.

Con todo eso en mente, su lógica de tiempo debería verse así:

 useEffect(() => { interval = setInterval(() => { setTime(time-1); console.log(timenow); }, tick); //runs once every tick return(() => clearInterval(interval)); //Once the component unmounts run some code to clear the interval }, [])

Ahora, en otro enlace useEffect, puede observar los cambios en el tiempo y actualizar el resto de su aplicación en consecuencia.

Este enfoque debería ser mucho más confiable porque no depende de reaccionar para actualizar el tiempo.

about 4 years ago · Juan Pablo Isaza Relatório

0

#La solución

 const component =() => { const [val, setval]= useState(globalState.get()); useEffect(() => { setVal(globalState.get()); globalState.subscribe(newVal=> setVal(newVal)); }); return <span>{val}</span> }
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda