REECT:SetInterval即使使用Clear Interval清除计时器后也不会停止

发布于 01-20 23:18 字数 493 浏览 2 评论 0原文

我制作了一个基本的幻灯片演示,其中选中复选框幻灯片已启用。问题是,一旦启用幻灯片放映,即使我取消选中该复选框,也无法禁用它。据了解,我正在学习计时器,并取消存储计时器的状态,但幻灯片继续播放。

具体来说,这部分在复选框更新时被调用:

useEffect(() => {
  if (isTrue) {
    setSlideTimer(() => {
      return setInterval(() => {
        forwardButton.current.click();
      }, slideDuration);
    });
  } else {
    clearInterval(slideTimer);
    setSlideTimer(null);
  }
}, [isTrue]);

从浏览器日志可以明显看出,计时器确实被清除了。虽然有警告“...组件正在更改要控制的复选框类型的不受控制的输入”,但我不确定这是否是罪魁祸首。

I have made a basic slideshow demo where on checking the checkbox slideshow is enabled. Problem is that once enabled slide show can't be disabled even if I uncheck the checkbox. As per muy understanding, I'm learning the timer and also nullifying the state storing the timer but the slide show keep on going.

Specifically this part gets invoked on checkbox update:

useEffect(() => {
  if (isTrue) {
    setSlideTimer(() => {
      return setInterval(() => {
        forwardButton.current.click();
      }, slideDuration);
    });
  } else {
    clearInterval(slideTimer);
    setSlideTimer(null);
  }
}, [isTrue]);

From browser logs it is evident that timer indeed got cleared. Though there is a warning "... component is changing an uncontrolled input of type checkbox to be controlled" but I'm not sure if that's the culprit here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

贪恋2025-01-27 23:18:03

问题

问题是,您缺少对slidertimer状态的依赖性。

useEffect(() => {
    if (isTrue) {
      setSlideTimer(() => {
        return setInterval(() => {
          forwardButton.current.click();
        }, slideDuration);
      });
    } else {
      clearInterval(slideTimer);
      setSlideTimer(null);
    }
  }, [isTrue]);

解决方案

通常不会将计时器ID存储在状态下。使用React Ref是您需要访问Timer ID 外部 useFeffect钩子,否则只需在useffect hook的回调中局部缓存。在这种情况下,您将需要使用ref保存slidertimer ID值,因此在组件卸载的情况下也可以清除它。

示例:

const sliderTimerRef = React.useRef();

useEffect(() => {
  // Clear any running intervals on component unmount
  return () => clearInterval(sliderTimerRef.current);
}, []);

useEffect(() => {
  if (isTrue && forwardButton.current) {
    sliderTimerRef.current = setInterval(
      forwardButton.current.click,
      slideDuration
    );
  } else {
    clearInterval(sliderTimerRef.current);
  }
}, [isTrue]);

附加问题

从浏览器日志中,很明显计时器确实被清除了。尽管
有一个警告“ ...组件正在更改要控制的类型复选框的不受控制的输入”,但我不确定这是否是
罪魁祸首。

通常情况下,当value检查 prop从未定义的变为定义的值更改时,情况通常是这种情况。确保最初定义的检查状态是什么,即使只是false

Issue

The issue is that you've a missing dependency on the sliderTimer state.

useEffect(() => {
    if (isTrue) {
      setSlideTimer(() => {
        return setInterval(() => {
          forwardButton.current.click();
        }, slideDuration);
      });
    } else {
      clearInterval(slideTimer);
      setSlideTimer(null);
    }
  }, [isTrue]);

Solution

Don't generally store timer ids in state. Use a React ref is you need to access the timer id outside the useEffect hook, otherwise just cache it locally within the useEffect hook's callback. In this case you will want to use a ref to hold the sliderTimer id value so it can also be cleared in the case the component unmounts.

Example:

const sliderTimerRef = React.useRef();

useEffect(() => {
  // Clear any running intervals on component unmount
  return () => clearInterval(sliderTimerRef.current);
}, []);

useEffect(() => {
  if (isTrue && forwardButton.current) {
    sliderTimerRef.current = setInterval(
      forwardButton.current.click,
      slideDuration
    );
  } else {
    clearInterval(sliderTimerRef.current);
  }
}, [isTrue]);

Additional issue

From browser logs it is evident that timer indeed got cleared. Though
there is a warning "... component is changing an uncontrolled input of type checkbox to be controlled" but I'm not sure if that's the
culprit here.

This is typically the case when the value or checked prop changes from an undefined to a defined value. Ensure whatever the checked state is that it is initially defined, even if just false.

浪荡不羁2025-01-27 23:18:03

尝试一下!

  useEffect(() => {
    let interval;
    if (isChecked) {
      interval = setInterval(() => {
        forwardButton.current.click();
      }, 1000); // change it
    }

    return function cleanup() {
      clearInterval(interval);
      console.log('Clear timer');
    };
  }, [isChecked]);

Try this!

  useEffect(() => {
    let interval;
    if (isChecked) {
      interval = setInterval(() => {
        forwardButton.current.click();
      }, 1000); // change it
    }

    return function cleanup() {
      clearInterval(interval);
      console.log('Clear timer');
    };
  }, [isChecked]);

南冥有猫2025-01-27 23:18:03

另一种方法是使用 setTimeout() 方法。为此,您需要创建一个新的状态clicks(或任何其他名称),每次更改时都会触发useEffect,从而允许setTimeout用作 setInterval

const [clicks, setClicks] = useState(0)

useEffect(() => {
  if(isChecked){
    setTimeout(() => { 
      forwardButton.current.click()
      setClicks(clicks + 1)
    }, slideDuration)
  }
}, [isChecked, clicks])

Another approach is to use the setTimeout() method. For this you would need to create a new state clicks (or any other name) that will trigger the useEffect every time it changes, allowing setTimeout to work as setInterval

const [clicks, setClicks] = useState(0)

useEffect(() => {
  if(isChecked){
    setTimeout(() => { 
      forwardButton.current.click()
      setClicks(clicks + 1)
    }, slideDuration)
  }
}, [isChecked, clicks])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文