I am attempting to clear a former timeout before initiating a new timeout, because I want messages to display for 4 seconds and disappear UNLESS a new message pops up before the 4 seconds is up. The Problem: Old timeouts are clearing the current message, so clearTimeout() is not working in this ponent, in this scenario:
let t; // "t" for "timer"
const [message, updateMessage] = useState('This message is to appear for 4 seconds. Unless a new message replaces it.');
function clearLogger() {
clearTimeout(t);
t = setTimeout(() => {
console.log('wiping message');
updateMessage('');
}, 4000);
}
function initMessage(msg) {
updateMessage(msg);
clearLogger();
}
The funny thing is that this works:
function clearLogger() {
t = setTimeout(() => {
console.log('wiping message');
updateMessage('');
}, 4000);
clearTimeout(t);
}
...but obviously defeats the purpose, since it just immediately obliterates the timeout. In practice, I should be able to trigger initMessage() every two seconds and never see, "wiping message' logged to the console.
I am attempting to clear a former timeout before initiating a new timeout, because I want messages to display for 4 seconds and disappear UNLESS a new message pops up before the 4 seconds is up. The Problem: Old timeouts are clearing the current message, so clearTimeout() is not working in this ponent, in this scenario:
let t; // "t" for "timer"
const [message, updateMessage] = useState('This message is to appear for 4 seconds. Unless a new message replaces it.');
function clearLogger() {
clearTimeout(t);
t = setTimeout(() => {
console.log('wiping message');
updateMessage('');
}, 4000);
}
function initMessage(msg) {
updateMessage(msg);
clearLogger();
}
The funny thing is that this works:
function clearLogger() {
t = setTimeout(() => {
console.log('wiping message');
updateMessage('');
}, 4000);
clearTimeout(t);
}
...but obviously defeats the purpose, since it just immediately obliterates the timeout. In practice, I should be able to trigger initMessage() every two seconds and never see, "wiping message' logged to the console.
Share Improve this question asked Sep 18, 2019 at 15:12 Gabriel KunkelGabriel Kunkel 2,7617 gold badges31 silver badges49 bronze badges 1-
1
Have you tried calling
clearLogger()
beforeupdateMessage()
? – ChrisG Commented Sep 18, 2019 at 15:23
4 Answers
Reset to default 8The issue is that on every render the value of t
is reset to null. Once you call updateMessage
, it will trigger a re-render and will lose it's value. Any variables inside a functional react ponent get reset on every render (just like inside the render
function of a class-based ponent). You need to save away the value of t
using setState
if you want to preserve the reference so you can call clearInterval
.
However, another way to solve it is to promisify setTimeout
. By making it a promise, you remove needing t
because it won't resolve until setTimeout
finishes. Once it's finished, you can updateMessage('')
to reset message
. This allows avoids the issue that you're having with your reference to t
.
clearLogger = () => {
return new Promise(resolve => setTimeout(() => updateMessage(''), resolve), 5000));
};
const initMessage = async (msg) => {
updateMessage(msg);
await clearLogger();
}
I solved this with useEffect. You want to clear the timeout in the return function
const [message, updateMessage] = useState(msg);
useEffect(() => {
const t = setTimeout(() => {
console.log('wiping message');
updateMessage('');
}, 4000);
return () => {
clearTimeout(t)
}
}, [message])
function initMessage(msg) {
updateMessage(msg);
}
You can use refs for this;
const timeoutRef = useRef<any>();
const clearLogger = () => {
clearTimeout(timoutRef.current);
timeoutRef.current = setTimeout(() => {
console.log('wiping message');
updateMessage('');
}, 4000)
}
Try execute set timeout after clearTimeout() pletes
clearTimeout(someVariable, function() {
t = setTimeout(() => {
console.log('wiping message');
updateMessage('');
}, 4000);
});
function clearTimeout(param, callback) {
//`enter code here`do stuff
}
Or you can use .then() as well.
clearTimeout(param).then(function(){
t = setTimeout(() => {
console.log('wiping message');
updateMessage('');
}, 4000);
});