After I set the setIsRunning(false)
in the else statement, it is supposed to go out console.log('final call')
. but it keeps calling console.log('running'). anyone know what I am doing wrong here and how this can be fixed
const [val, setval] = useState(0)
const [isRunning, setIsRunning] = useState(true)
useEffect(() => {
let intervalId
if (isRunning) {
intervalId = setInterval(() => {
if (val <= 100) {
setval((t) => t 5)
} else {
console.log('call')
setIsRunning(false)
}
console.log('running') // This is being called continuously
}, 50)
} else {
console.log('final call')
}
return () => clearInterval(intervalId)
}, [isRunning])
Once the val
reaches 100 I want the setTimeout
to stop, but at the same time i dont want to use val
in my dependency. I want the interval to be cleared so that it does not run anymore
CodePudding user response:
Try my code
const [val, setval] = useState(0);
const [isRunning, setIsRunning] = useState(true);
useEffect(() => {
let intervalId;
if (isRunning) {
intervalId = setInterval(() => {
setval((t) => {
if (t <= 100) {
return (t = 5);
} else {
setIsRunning(false);
clearInterval(intervalId);
return t;
}
});
console.log('running'); // This is being called continuously
}, 50);
} else {
console.log('final call');
}
return () => clearInterval(intervalId);
}, [isRunning]);
CodePudding user response:
You have 2 problems in your code.
Don't pass state as the dependency of the useEffect.
Your if condition must be in the setInterval not out of it.
And as a suggestion, use Ref instead of State.
So this would work as expected:
const valRef = useRef(0)
const isRunningRef = useRef(true);
useEffect(() => {
let intervalId;
intervalId = setInterval(() => {
if (isRunningRef.current) {
if (valRef.current <= 100) {
valRef.current = 5;
} else {
console.log('call');
isRunningRef.current = false;
}
console.log('running');
} else {
console.log('final call');
clearInterval(intervalId);
}
}, 50)
return () => clearInterval(intervalId)
}, [])
CodePudding user response:
Quick fix
const [val, setval] = useState(0)
// const [isRunning, setIsRunning] = useState(true)
// use useRef if you dont want to react to changes in useEffect
const isRunningRef = useRef(true)
useEffect(() => {
let intervalId
if (isRunning.current) {
intervalId = setInterval(() => {
if (val <= 100) {
setval((t) => t 5)
} else {
console.log('call')
isRunning.current = false;
// stop the interval here if needed
clearInterval(intervalId)
}
console.log('running') // This is being called continuously
}, 50)
}
return () => {
if (intervalId !== undefined) {
// clear if only timer was set
clearInterval(intervalId)
}
}
}, []) // userRef varaibles not needed in depedency array
React beta docs explain the problem, but solution is provided using useEvent which is in RFC, so useRef can be used till then
Hope it solves your problem