This problem requires keen observation and know-how of the working of useEffect
.
Okay let's break this down, let's consider your code and see why it doesn't work:
let intervalID;
useEffect(() => {
intervalID = setInterval(() => {
setValue(value => value+1);
}, 100)
}, [])
We can notice that the dependency array is empty, meaning useEffect
runs only once when it is mounted. So right after the component is mounted, your useEffect
runs and the setInterval
is triggered to increment the value
every 100ms. Since there are no conditions given when to stop, this keeps going on forever. Further, you are not making use of the current
property on the intervalId
instance (Although it is not mandatory, it's a good practice).
In order to get this working, we'd want to add some conditions to stop the interval after the value
reaches 100. This condition can be checked when useEffect
is invoked every time after the value is incremented. To invoke useEffect
when value is incremented, we can add value
as a dependency array. Now that we're invoking the function, the next part is fairly simple and that is, checking if the value has reached 100 or not, this could be done using a simple if
condition.
Since we've added a dependency array to useEffect
and it runs whenever value
changes, it is important to clean up the previously created intervals, using clearInterval
. clearInterval
should be invoked before creating a new interval, and the best time to clear the interval is when it is unmounting.
So all-in-all you could do something like this:
export default function App() {
const [value, setValue] = useState(0);
let intervalID = useRef(null); //using useRef hook to maintain state changes across rerenders.
useEffect(() => {
if (value < 100) {
intervalID.current = setInterval(() => { //Proceed to set interval if value is less than 100
setValue((value) => value + 1);
}, 100);
}
return () => clearInterval(intervalID.current); //clear previous interval when unmounting.
}, [value]);
return (
<div className="App">
<h1>Hello{value}</h1>
</div>
);
}
Since an interval is created and destroyed during each mounting/unmounting phase, you could alternatively use setTimeout
also, which again would give the same result.