javascript 如何在接下来的n秒内每秒更新一个状态

hvvq6cgz  于 2023-01-16  发布在  Java
关注(0)|答案(3)|浏览(135)

我有一个状态变量resendTimemagicLinkState
我想在magicLinkState发送后的10秒钟内从setResendTime切换到resendTime - 1
我已经尝试了下面的代码,但这并不更新resendTime每一秒。

useEffect(() => {
  if (magicLinkState === "sent" && resendTime > 0) {
    const timer = setInterval(() => setResendTime(resendTime - 1), 1000);
    console.log(resendTime);
    return () => clearInterval(timer);
  }
}, []);

这段代码只更新第一秒的状态。我也尝试过传递依赖关系数组,但没有成功。我如何让它更新状态,以便我达到预期的效果。

rdlzhqv9

rdlzhqv91#

代码中的基本思想是正确的,但需要进行一些调整。
1.需要将magicLinkState添加到效果的依赖项中,否则在获取sent值时它不会触发,但只有在最初设置为该值时才会触发。
1.应该使用箭头语法:setResendTime((prevResendTime) => prevResendTime - 1),以便每次获取正确的状态值
1.在这个效果中不需要清除函数,因为你只想在它被触发并且减少10次到resendTime之后清除间隔。
1.您应该添加一些局部count变量,以便仅减少10次,而不是永远减少
在这些更改之后,您的代码应该如下所示:

const decreaseResentTime = (prevResendTime) => prevResendTime - 1;

 useEffect(() => {
    let timer;
    if (magicLinkState === "sent" && resendTime > 0) {
      let count = 0;
      timer = setInterval(() => {
        if (count < 10) {
          count++;
          setResendTime(decreaseResentTime );
        } else {
          clearInterval(timer);
        }
      }, 1000);
    }
  }, [magicLinkState]);

您可以在CodeSandbox中找到演示此解决方案的示例。
这里还有更多的改进要做,但它们是基于您的需要。例如,如果magicLinkState更改为“已发送”,然后更改为其他内容,然后在10秒内返回到“已发送”,2个间隔将运行并以双倍的速度减少。

tcomlyy6

tcomlyy62#

您只是遇到了初始resendTime状态值上的过时闭包问题。通过使用函数状态更新来正确访问以前的状态值(而不是周围回调作用域中关闭的任何值),可以很容易地解决这个问题。

const timerRef = React.useRef();

useEffect(() => {
  if (magicLinkState === "sent" && resendTime > 0) {
    const timer = setInterval(() => {
      setResendTime(resendTime => resendTime - 1); // <-- functional update
    }, 1000);
    timerRef.current = timer;
    
    return () => clearInterval(timer);
  }
}, []);

还要注意的是,由于闭包的原因,如果你想记录resendTime状态 as 它的更新,你需要使用另一个useEffect钩子,它有一个适当的依赖关系。这也是你需要移动逻辑来检查时间间隔是否完成的地方。使用React ref来存储对定时器id的引用。

useEffect(() => {
  if (resendTime <= 0) {
    clearInterval(timerRef.current);
  }
  console.log(resendTime);
}, [resendTime]);
cwdobuhd

cwdobuhd3#

我可以用时间戳代替时间间隔吗?这个函数调用一次后会检查10秒内的每一秒

useEffect(() => {
  if (magicLinkState === "sent" && resendTime > 0) {
    let startTimeforTenSeconds = Date.now();
    let startTimeforEachSecond = Date.now();

    const nonBlockingCommand = new Promise((resolve, reject) => {
        while(true) {
            const currentTime = Date.now();

            if (currentTime - startTimeforEachSecond >= 1000) {
              startTimeforEachSecond = Date.now();
              console.log("1 seconds have passed. set resend time here");
              // code for resending time here
              setResendTime(resendTime - 1);
              console.log(resendTime);
            }

            if (currentTime - startTimeforTenSeconds >= 10000) {
              console.log("10 seconds have passed. stop checking.");
              resolve("10 seconds have passed.");
              break;
            }
        }
    });

    nonBlockingCommand();
  }
}, []);

相关问题