首页 > 解决方案 > 为什么每次都使用 useEffect 清理日志记录?

问题描述

当用户导航到下一个屏幕以避免它的工作时,我正在实现倒计时并使用useRef钩子在清理 setTimeout 时使用它cancel all subscription warning

但是计数时我有一些奇怪的东西 - 1 我可以在控制台中看到“嘿”!虽然没有清理 setTimeOut!

在这种情况下我不想清理它,但为什么每次计数更改时都要登录!

代码片段

  const [seconds, setSeconds] = useState(40);
  const countRef = useRef(seconds);

  useEffect(() => {
    if (seconds > 0) {
      countRef.current = setTimeout(() => {
        setSeconds(seconds - 1);
      }, 1000);
    } else {
      setSeconds(0);
    }
    return () => {
      console.log('hey'); // every count down it's appeared 
      clearTimeout(countRef.current);
    };
  }, [seconds]);

标签: javascriptreactjsreact-nativereact-hooks

解决方案


您看到“嘿”是因为您使用秒作为依赖项。所以每次秒变化时,效果都必须再次运行,从而导致效果的销毁函数(您从效果返回的函数)被调用。

与其将秒作为依赖项,不如使用 setSeconds。

const [seconds, setSeconds] = React.useState(10);

useEffect(() => {
  let didUnsub = false;

  const id = setInterval(() => {
    setSeconds((prev) => {
      // while the count is greater than 0, continue to countdown
      if (prev > 0) {
        return prev - 1;
      }

      // once count eq 0, stop counting down
      clearInterval(id);
      didUnsub = true;

      return 0;
    });
  }, 1000);

  return () => {
    console.log("unmounting");
    // if the count didn't unsubscribe by reaching 0, clear the interval
    if (!didUnsub) {
      console.log("unsubscribing");
      clearInterval(id);
    }
  };
}, [setSeconds]);

如果您查看下面的示例,您会看到效果仅在安装组件时运行一次。如果您要使组件卸载,则会调用destroy 函数。这是因为 setState 是一个调度函数,在渲染之间不会改变,因此不会导致效果被连续调用。

在示例中,您可以单击按钮在安装和拆卸计数器之间切换。当您卸载它时,请注意它会登录控制台。

示例:https ://codesandbox.io/s/gallant-silence-ui0pv?file=/src/Countdown.js


推荐阅读