Estoy usando setInterval y clearInterval en un componente funcional de React. Estoy incrementando el conteo dentro de setInterval y quiero clearInterval una vez que haya alcanzado cierto valor. Pero no se está borrando, no estoy seguro de lo que estoy haciendo mal.
const { useState, useEffect } = React; /*export default*/ function App() { const [chartsCount, setChartsCount] = useState(1); useEffect(() => { const chartsCountId = setInterval(() => { setChartsCount((count) => { console.log('set chart count function is running ', { chartsCount }); if (chartsCount >= 3/*16*/) { console.log('We have reached the limit'); clearInterval(chartsCountId); } return count + 1; }); }, 1000); return () => { clearInterval(chartsCountId); }; }, [chartsCount]); return ( <div> <h1>Hello StackBlitz!</h1> <p>Start editing to see some magic happen :)</p> </div> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />); <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>Debe manejar la lógica fuera de setState, ya que está incluyendo el count en las dependencias del efecto, no necesita leer el estado nuevo en una devolución de llamada:
const { useState, useEffect } = React; /*export default*/ function App() { const [chartsCount, setChartsCount] = useState(1); useEffect(() => { const chartsCountId = setInterval(() => { if (chartsCount >= 3 /*16*/ ) { // *** console.log('We have reached the limit'); clearInterval(chartsCountId); } else { setChartsCount(c => c + 1); console.log("Current count: ", chartsCount ) } }, 1000); return () => { clearInterval(chartsCountId); }; }, [chartsCount]); // *** return ( <div> <h1>Hello StackBlitz!</h1> <p>Start editing to see some magic happen :)</p> </div> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />); <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>O si solo desea una solución simple y rápida para su código:
setChartsCount((count) => { console.log('set chart count function is running ', { chartsCount }); if (chartsCount >= 3/*16*/) { console.log('We have reached the limit'); clearInterval(chartsCountId); return count } return count + 1; });Básicamente, está configurando el mismo conteo si alcanza el límite, y eso evitará que el efecto vuelva a ejecutarse.
El problema es que ha hecho que chartsCount dependa de useEffect , por lo que cada vez que cambia se cancela un intervalo y se inicia otro. Eso incluye cuando el conteo ha superado el límite, ya que en ese caso todavía está agregando al conteo.
En cambio:
chartsCount una dependencia del efecto, ycount (el parámetro si su devolución de llamada setChartsCount ) en lugar de chartsCount en su código de efecto Fragmento actualizado, vea los cuatro comentarios con *** :
const { useState, useEffect } = React; /*export default*/ function App() { const [chartsCount, setChartsCount] = useState(1); useEffect(() => { const chartsCountId = setInterval(() => { setChartsCount((count) => { console.log('set chart count function is running ', { chartsCount: count }); // *** if (count >= 3/*16*/) { // *** console.log('We have reached the limit'); clearInterval(chartsCountId); return count; // *** >>IF<< you don't want count incremented the last time } return count + 1; }); }, 1000); return () => { clearInterval(chartsCountId); }; }, []); // *** return ( <div> <h1>Hello StackBlitz!</h1> <p>Start editing to see some magic happen :)</p> </div> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />); <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>