Quiero que el siguiente código comience la cuenta regresiva desde un número después de que un usuario inicie sesión.
El siguiente código muestra 0 simples en el archivo console.log cada segundo, pero no parece establecer la variable de estado secondsLeft en 8, ni cuenta esta variable hacia atrás.
const [secondsLeft, setSecondsLeft] = useState(0);...
const handleButton = async () => { const response = await fetch('http://localhost:5001/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); setUsername(''); setPassword(''); if (response.ok) { const data = await response.json(); setCurrentUser(prev => ({ ...prev, ...data.user })); setMessage(`User: ${currentUser.firstName}`); setSecondsLeft(8); setInterval(() => { setSecondsLeft(prev => secondsLeft -1); console.log(secondsLeft); }, 1000); } else { setMessage('bad login'); } } ¿Cómo puedo obtener setInterval para disminuir el valor de los secondsLeft cada segundo?
Esta es una trampa muy común en React. Usted, comprensiblemente, parece asumir que setSecondsLeft surte efecto inmediatamente, pero no es así. Por lo tanto, secondsLeft no será 8 para empezar. Hay otro problema de que secondsLeft no se actualiza en su intervalo. Esto debería funcionar en su lugar:
setSecondsLeft(8); setInterval(() => { setSecondsLeft(prev => { console.log(prev); return prev - 1; }); }, 1000);En realidad funciona, pero se ve en la consola 8 cada vez que se ejecuta la devolución de llamada de setIntervall, porque solo accede al valor inicial de segundos restantes y no reconoce la actualización de segundos restantes en actualizaciones posteriores. Puede ejecutar el siguiente ejemplo y ver cómo se actualiza el estado cada vez que se ejecuta la devolución de llamada de Time setInterval, pero en la consola siempre ve 0.
function App() { const [secondsLeft, setSeconds] = React.useState(0); let timerId = null; const handleClick = () => { setSeconds(8); timerId = setInterval(()=> { console.log(secondsLeft) setSeconds(prev => prev - 1); }, 1000) }; React.useEffect(()=> { return ()=> clearInterval(timerId) }, []) return ( <div> <h2>{secondsLeft}</h2> <button onClick={handleClick}>Start interval</button> </div> ); } ReactDOM.render(React.createElement(App, {}), document.getElementById("root")); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script> <div id="root"></div>Traté de hacer las cosas de la manera tradicional,
useEffect(() => { setInterval(() => { console.log("update", st); setSt((prev) => prev + 1); }, 500); }, []); Pero esto no funciona porque durante la ejecución de useState en el primer render, setInterval guarda una copy of prev para sí mismo que intenta actualizar una y otra vez, por ejemplo: setSt(prev => prev+1) pero desde prev siempre es = 1 debido al cierre que tiene para sí mismo, el valor realmente no se actualiza.
Luego traté de usar useCallback hook que vuelve a representar la function en el cambio de dependencia y, por lo tanto, brindó prev como dependencia, pero lamentablemente eso tampoco funcionó probablemente debido a la misma razón que la anterior pero por diferentes medios.
Puede ver la forma en que lo intenté en el código comentado de codesandbox .
Por fin, probé mis manos creando un setIntervalHack que puede funcionar de manera similar a setInterval, pero no es realmente un setInterval.
Aquí están los pasos que seguí.
setInterval as a recursive que se ejecuta una y otra vez después de un intervalo , pero el inconveniente es que no podemos pasarle un argumento debido a que la actualización se vuelve obsoleta.setIntervalHack que representa el nuevo estado con el que se actualizará.await a que se ejecutara la recursividad nuevamente y en el argumento de recordar la función recursiva setIntervalHack , pasé (currentState+1) y esta es la forma en que traté de lograr la funcionalidad similar de setInterval
Aquí está el enlace al código https://codesandbox.io/s/happy-swartz-ikqdn?file=/src/focus.js
Nota: puede ir a /focus route en codesandbox's browser y abrir la consola
PD: Hice un incremento en el contador, no el decremento. Puede hacer lo mismo disminuyendo en cada recursión