I am using setInterval
and clearInterval
in a React functional component. I am incrementing the count inside the setInterval
and want to clearInterval
once it has reached certain value.but it is not clearing out, not sure what I am doing wrong.
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>
CodePudding user response:
You shoud handle the logic outside the setState, since you are including the count
in the deps of the effect you don't need to read the fresh state in a callback:
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>
Or fi you want just a simple and quick fix to your code:
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;
});
Basically you are setting the same count if you reach the limit, and that will prevent the effect from running again.
CodePudding user response:
The problem is that you've made chartsCount
a dependency on the useEffect
, so every time it changes one interval is canceled and another is started. That includes when the count has gone above the limit, since you're still adding to the count in that case.
Instead:
- Don't make
chartsCount
a dependency of the effect, and - Use
count
(the parameter if yoursetChartsCount
callback) rather thanchartsCount
in your effect code
Updated snippet, see the four comments with ***
:
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>