最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why is clearTimeout not clearing the timeout in this react component? - Stack Overflow

programmeradmin8浏览0评论

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() before updateMessage()? – ChrisG Commented Sep 18, 2019 at 15:23
Add a ment  | 

4 Answers 4

Reset to default 8

The 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);
});
发布评论

评论列表(0)

  1. 暂无评论