En primer lugar, no pude resolver el problema en este fragmento de código. Pero probablemente el tema tiene un lugar aquí.
Como pude entender, el problema podría ser que el valor del contador no se actualiza después de hacer clic en el botón. La alerta muestra el valor cuando se hizo clic en el botón, aunque durante el retraso de 2,5 segundos hice clic y aumenté el valor del contador.
¿Estoy en lo correcto y, de ser así, qué se debe corregir o agregar aquí?
import React, { useState } from 'react' function Root() { const [count, setCount] = useState(0) function handleAlertClick() { setTimeout(() => { alert(`You clicked ${count} times`) }, 2500) } return ( <Container> <Column> <h4>Closures</h4> <p>You clicked {count} times</p> <button type="button" onClick={() => setCount(counter => counter + 1)}> Click me </button> <button type="button" onClick={handleAlertClick}> Show alert </button> </Column> </Container> ) } export default RootProblema
Cuando se llama a setTimeout , su función de devolución de llamada se cierra sobre el valor actual del count en el renderizado actual del componente Root .
Antes de que caduque el temporizador, si actualiza el count , se vuelve a procesar el componente, PERO la función de devolución de llamada de setTimeout todavía ve el valor que estaba en vigor cuando se llamó a setTimeout . Esta es la esencia del problema causado por el cierre en su código.
Cada representación del componente Root tiene su propio estado, accesorios y funciones locales definidas dentro del componente; en resumen, cada renderizado de un componente está separado de los anteriores.
El estado es constante dentro de una representación particular de un componente; el componente no puede ver el estado actualizado hasta que se vuelve a renderizar. Cualquier temporizador establecido en el renderizado anterior verá el valor que cerró ; no puede ver el estado actualizado.
Solución
Puede usar el gancho useRef para deshacerse del problema causado por el cierre.
Puede actualizar la referencia cada vez que se vuelve a renderizar el componente Root . Esto nos permite guardar el último valor de count en la ref.
Una vez que tenga un árbitro, en lugar de pasar la count para alert , pase el árbitro. Esto asegura que alert siempre muestre el último valor de count .
function Root() { const [count, setCount] = React.useState(0) const countRef = React.useRef(count); // assign the latest value of "count" to "countRef" countRef.current = count; function handleAlertClick() { setTimeout(() => { alert(`You clicked ${countRef.current} times`) }, 2500) } return ( <div> <h4>Closures</h4> <p>You clicked {count} times</p> <button type="button" onClick={() => setCount(counter => counter + 1)}> Click me </button> <button type="button" onClick={handleAlertClick}> Show alert </button> </div> ) } ReactDOM.render(<Root/>, document.getElementById("root")); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script> <div id="root"></div>