react state updated values are shown in use Effect but inside function only shown an old value.
const [counter, setCounter] = useState(0);
I am trying to update the counter value inside a set interval function
const handleIncrease = () => {
clearInterval(intervalval);
if (counter < 10) {
let increment = setInterval(() => {
console.log("isCounterContinue@handleIncrease", counter);
setCounter((prev) => prev + 1);
}, 1000);
setIntervalval(increment);
}
}; inside useEffect updated values are shown. but inside function handleIncrease only show the old value Basically, I am trying to do counter value is not increase when it's more than 30.
code Link : https://codesandbox.io/s/bold-cdn-zzbs2?file=/src/App.js
handleIncrease
is only called when a button is clicked, with the current state. There is nothing to update in the click handler. I think what you are really after is accessing the updated counter
state in the interval's callback, which "ticks" once every second. Or more accurately, respond to the isCounterContinue
state toggling false to stop the interval when a limit is hit.
Use a ref to hold a reference to the interval timer and set/clear using this instead of a state that goes stale in enclosures.
const Timer = () => {
const [counter, setCounter] = useState(0);
const intervalRef = useRef();
useEffect(() => {
console.log({ counter });
if (counter >= 5) {
clearInterval(intervalRef.current);
}
}, [counter]);
const handleIncrease = () => {
clearInterval(intervalRef.current);
intervalRef.current = setInterval(() => {
setCounter((prev) => prev + 1);
}, 1000);
};
const handleDecrease = () => {
clearInterval(intervalRef.current);
intervalRef.current = setInterval(() => {
setCounter((prev) => prev - 1);
}, 1000);
};
const handleStop = () => {
clearInterval(intervalRef.current);
};
return (
<>
<div>{counter}</div>
<div>
<button onClick={handleDecrease}>Decrease</button>
<button onClick={handleStop}>Stop</button>
<button onClick={handleIncrease}>Increase</button>
</div>
</>
);
};
Suggestion
The increment/decrement handlers are basically identical other than what they add to the count. Use a curried function to handle both cases by closing over an incrementing value. Since the "stop" handler shares logic to clear the interval, use the fact that 0
is a falsey value and only restart an interval timer for truthy (i.e. non-zero) number values and use one single handler for all three buttons.
const handleIncrease = (val) => () => {
clearInterval(intervalRef.current);
if (val) {
intervalRef.current = setInterval(() => {
setCounter((prev) => prev + val);
}, 1000);
}
};
...
<button onClick={handleIncrease(-1)}>Decrease</button>
<button onClick={handleIncrease(0)}>Stop</button>
<button onClick={handleIncrease(1)}>Increase</button>