为什么在clearTimeout之后SetTimeout代码仍然执行

IT技术 javascript reactjs
2021-05-19 04:04:36

我的react组件中有以下代码:

//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]);

我在控制台中得到的输出:

test1
test3
test2 //after 15 seconds

所以我试图开始超时,它会记录“test2”,如果在此期间超时未被清除。正如我们所看到的,'test3' 已被记录,这意味着超时已被清除,但 15 秒后仍会记录 'test2'。这里有什么问题?

2个回答

您需要ref像这样保存超时,每次组件重新渲染时都会有一个新的超时实例,这就是为什么当您clearTimeout它不起作用,因为它清除了错误的计时器:

  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]);

上面的代码输出这个:

test1 

setting 

test3 

setting 

你可以在这里试试:https : //codesandbox.io/s/boring-waterfall-6f6iv?file=/src/App.js

您需要一个钩子清理函数来处理,这将在卸载组件时删除 clearTimeout 并且您不需要全局变量。

像这样尝试。

  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]);

演示链接在这里