我正在用React构建一个简单的时钟应用程序.目前countDown()功能正常,但我希望用户能够通过按下按钮来停止/启动时钟.我有一个名为paused的状态布尔值,当用户点击一个按钮时,它会反转.问题在于,在paused的值被反转后,传递给setInterval()countDown()函数中对paused的引用似乎正在访问默认值paused,而不是更新后的值.

function Clock(){
  const [sec, setSecs] = useState(sessionLength * 60);
  const [paused, setPaused] = useState(false);
 
  const playPause = () => {
    setPaused(paused => !paused);
  };
  
  const countDown = () => {
    if(!paused){
        setSecs(sec => sec - 1)
      }
  }
  
  useEffect(() => {
    const interval = setInterval(() => {
        countDown();
    }, 1000);
    return () => {
      clearInterval(interval);
    };
  }, []);

我假设这与React中调用setState()的异步性质有关,和/或使用正则表达式时作用域/上下文的性质有关.然而,我无法通过阅读与这些概念相关的文档来确定发生了什么.

我可以想出一些变通办法,让我的应用程序按预期运行.然而,我想了解我目前的方法有什么问题.我希望任何人都能对此有所了解!

推荐答案

在代码中,安装组件时只调用一次useEffect.

内部注册的倒计时函数将在调用useEffect/setInterval时具有其初始值.因此,paused仅在您最初安装组件时才具有该值.因为您没有直接调用倒计时或更新useEffect中的倒计时值,所以它不会被更新.

我想你可以这样解决这个问题:

  interval.current = useRef(null);
  const countDown = () => {
    if(!paused){
        setSecs(sec => sec - 1)
      }
  }
  
  useEffect(() => {
    clearInterval(interval.current);
    interval.current = setInterval(countDown, 1000);
    return () => {
      clearInterval(interval.current);
    };
  }, [paused]);

您的useEffect取决于paused的值,因为它需要创建一个新的间隔(使用不同的倒计时函数).这不仅会在坐骑上触发useEffect,而且每次paused改变时都会触发.因此,一种解决方案是清除间隔,并使用不同的回调函数启动一个新的间隔.

Edit:实际上,你可以改进它,因为你只想在倒计时功能确实起作用的情况下运行间隔,所以这也应该起作用:

 useEffect(() => {
    clearInterval(interval.current);
    if(!paused) {
      interval.current = setInterval(countDown, 1000);
    }
    return () => {
      clearInterval(interval.current);
    };
  }, [paused]);

Javascript相关问答推荐

对象和数字减法会抵消浏览器js中的数字

窗口.getComputedStyle()在MutationObserver中不起作用

过滤对象数组并动态将属性放入新数组

react/redux中的formData在expressjs中返回未定义的req.params.id

. NET中Unix时间转换为日期时间的奇怪行为

如何在不影响隐式类型的情况下将类型分配给对象?

Reaction Redux&Quot;在派单错误中检测到状态Mutations

OpenAI转录API错误请求

如果没有页面重新加载Angular ,innerHTML属性绑定不会更新

更新Redux存储中的对象数组

Phaser3 preFX addGlow不支持zoom

如何使用Reaction路由导航测试挂钩?

连续添加promise 时,如何在所有promise 都已结算时解除加载覆盖

需要RTK-在ReactJS中查询多个组件的Mutations 数据

JavaScript:多个图像错误处理程序

更改管线时不渲染组件的react

KeyboardEvent:检测到键具有打印的表示形式

Rails 7:在不使用导入映射的情况下导入Java脚本

已在EventListener中更新/更改异步的React.js状态对象,但不会导致组件重新呈现

在Java脚本/类型脚本中覆盖父构造函数中的默认值