为什么clearTimeout不清除此React组件中的超时?

Gab*_*kel 5 javascript settimeout reactjs cleartimeout

我尝试在启动新超时之前清除以前的超时,因为我希望消息显示4秒钟,然后消失,除非在4秒钟之前弹出新消息。问题:在这种情况下,旧超时正在清除当前消息,因此clearTimeout()在此组件中不起作用:


  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();
  }

Run Code Online (Sandbox Code Playgroud)

有趣的是,这有效:

  function clearLogger() {
    t = setTimeout(() => {
      console.log('wiping message');
      updateMessage('');
    }, 4000);
    clearTimeout(t);
  }
Run Code Online (Sandbox Code Playgroud)

...但显然无法达到目的,因为它立即消除了超时。在实践中,我应该能够每两秒钟触发一次initMessage(),并且永远不会看到“擦除消息”记录到控制台。

tec*_*995 8

问题是在每次渲染时, 的值t都会重置为 null。一旦你调用updateMessage,它将触发重新渲染并失去它的价值。函数式 React 组件内的任何变量都会在每次渲染时重置(就像在render基于类的组件的函数内一样)。如果您想保留引用以便可以调用,则需要保存tusing的值。setStateclearInterval

然而,解决这个问题的另一种方法是承诺setTimeout。通过做出承诺,您就消除了需求t,因为它在完成之前不会得到解决setTimeout。完成后,您可以updateMessage('')重置message。这可以避免您在引用时遇到的问题t

clearLogger = () => {
  return new Promise(resolve => setTimeout(() => updateMessage(''), resolve), 5000));
};

const initMessage = async (msg) => {
  updateMessage(msg);
  await clearLogger();
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案提醒我,**t** 每次渲染都会消失。我通过消除 useEffect 中的一些设置来稍微调整应用程序的功能。useEffect 间接运行 **clearLogger**,因此运行它会重新渲染。 (2认同)

小智 6

我用 useEffect 解决了这个问题。您想清除返回函数中的超时

const [message, updateMessage] = useState(msg);

useEffect(() => {
  const t = setTimeout(() => {
    console.log('wiping message');
    updateMessage('');
  }, 4000);

  return () => {
    clearTimeout(t)
  }
}, [message])



function initMessage(msg) {
  updateMessage(msg);
}
Run Code Online (Sandbox Code Playgroud)