I don’t understand why currentExpVal
is always has a value of 0
. It means the interval doesn’t stop. Could anybody explain it?
I want to have a smoothly updating counter during interval until it’s not 10 (for example).
import React, { useEffect, useRef, useState } from "react";
import styles from "./Experience.module.scss";
type Props = {};
export const Experience: React.FC<Props> = (props: Props) => {
const expValueRef = useRef(10);
const [currentExpVal, setCurrentExpVal] = useState(0);
useEffect(() => {
const intervalRef = setInterval(() => {
// console.info(currentExpVal, expValueRef.current)
if (currentExpVal < expValueRef.current) {
console.info(currentExpVal, expValueRef.current);
setCurrentExpVal((prev) => {
return prev + 1;
});
} else {
console.info("clear");
clearInterval(intervalRef);
}
}, 1500);
}, []);
// currentExpVal is not updated within if (currentExpVal < expValueRef.current)
return (
<div className={styles["exp-wrapper"]}>
{currentExpVal}
</div>
);
};
2
Answers
Your effect runs only once due to the empty array
[]
in your effect dependency, so inside your effectcurrentExpVal
references the very first value of the state variable, that’s why it’s always 0.I would split the work in 2 effects, one to init the interval and another to check if the limit is reached.
I suggest you to use eslint-plugin-react-hooks to prevent this kind of error. It would have warned you that you forgot to pass
currentExpVal
in the effect dependencies.The problem you have is a closure one, which occurs especially when used with
setInterval
. When theuseEffect
hook is run for the first time, the current value ofcurrentExpVal
is captured and is 0 at that point. Inside thesetInterval
, this value never gets updated; hence you always see the 0 value.You can use the
setCurrentExpVal
callback to access the latest state. You already use that but you’re comparing the wrong values. Instead of comparingcurrentExpVal
andexpValueRef.current
, you can compare the current state within the updater function.The solution above that @Olivier gave is also valid. Here is the other one: