I have the following problem with the useInterval hook, Im trying to make the counter stop if it hits count 20, but it seems that the way im currently implementing it it seems to cause infinite loop of render. here is my code so far:
import React, { ChangeEvent, useState } from "react";
import { useInterval } from "usehooks-ts";
export default function Component() {
// The counter
const [count, setCount] = useState<number>(0);
// Dynamic delay
const [delay, setDelay] = useState<number>(1000);
// ON/OFF
const [isPlaying, setPlaying] = useState<boolean>(true);
useInterval(
() => {
// Your custom logic here
setCount(count 1);
},
// Delay in milliseconds or null to stop it
isPlaying ? delay : null
);
if (count === 10) {
setPlaying(false);
}
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setDelay(Number(event.target.value));
};
return (
<>
<h1>{count}</h1>
<button onClick={() => setPlaying(!isPlaying)}>
{isPlaying ? "pause" : "play"}
</button>
<p>
<label htmlFor="delay">Delay: </label>
<input
type="number"
name="delay"
onChange={handleChange}
value={delay}
/>
</p>
</>
);
}
I can't grasp on why this wont work, could someone explain and show me what im doing wrong?
CodePudding user response:
The following block in the code is what's causing the infinite loop, as on every render after the count is 10 and counter is paused, setPlaying(false)
will be executed every time and will cause re render everytime, thus cause the infinite loop
if (count === 10) {
setPlaying(false);
}
Instead you can move this block to a use effect as
useEffect(() => {
if (count === 10) {
setPlaying(false);
}
}, [count]);
Please find codesandbox for reference
CodePudding user response:
With a useEffect hook :
useEffect(() => {
if (count === 10) {
setPlaying(false);
}
}, [count])
Every time count changes, useEffect will trigger and check if count has reached 10.
You may also prevent user from changing state above 10 :
<button onClick={() => setPlaying(count === 10 ? false : !isPlaying)}>
CodePudding user response:
each update state or props cause to create a new interval.
If you have to use interval
let myinterval = useInterval(
() => {
// Your custom logic here
setCount(count 1);
},
// Delay in milliseconds or null to stop it
isPlaying ? delay : null
);
clearInterval(myinterval);
you put this code to useEffect
useEffect(()=>{
if(count <20){
let myinterval = useInterval(
() => {
// Your custom logic here
setCount(count 1);
},
// Delay in milliseconds or null to stop it
isPlaying ? delay : null
);
clearInterval(myinterval);
}
},[count])