Reputation: 337
I have following code in my react component:
//some code
var timeout = null; //global variable
//some more code
useEffect(() => {
if(...some condition) {
console.log('test1');
timeout = setTimeout(() => {
console.log('test2');
}, 15 * 1000);
} else {
console.log('test3');
clearTimeout(timeout);
}
}, [some other condition]);
The output I get in the console:
test1
test3
test2 //after 15 seconds
So I am trying to start timeout which will log 'test2', if in the meantime timeout was not cleared. As we can see 'test3' is logged, meaning timeout was cleared, but still 'test2' is logged after 15 seconds. What is the issue here?
Upvotes: 3
Views: 3512
Reputation:
You need to save timeout in a ref
like this, everytime the component rerenders there is a new instance of timeout and that's why when you clearTimeout
it doesn't work, because it clears a wrong timer:
const timeout = useRef(null); //global variable
const [test, setTest] = useState(true);
//some more code
setTimeout(() => {
console.log("setting");
setTest(false);
}, 2000);
useEffect(() => {
if (test) {
console.log("test1");
timeout.current = setTimeout(() => {
console.log("test2");
}, 5 * 1000);
} else {
console.log("test3");
clearTimeout(timeout.current);
}
return () => clearTimeout(timeout.current) // clearing on unmount
}, [test]);
the code above outputs this:
test1
setting
test3
setting
you can try it here: https://codesandbox.io/s/boring-waterfall-6f6iv?file=/src/App.js
Upvotes: 3
Reputation: 4470
You need a hook cleanup function to handle, this will remove clearTimeout while Unmounting the component and Also you don't need global variable.
Try like this.
const [test, setTest] = useState(true);
// Trigger change
setTimeout(() => {
setTest(false);
}, 2000);
useEffect(() => {
let timeout = null
console.log("test1")
if (test) {
timeout = setTimeout(() => {
console.log("test2");
}, 15 * 1000);
}
return () => { // Needs cleanup function
clearTimeout(timeout);
}
}, [test]);
Demo link is here
Upvotes: 0