首页 > 解决方案 > 为什么在 useEffect() 内部使用时 setTimeout() 不起作用并按预期返回值?

问题描述

我正在做一个倒计时。简而言之,这个时钟将允许用户选择时间,当按钮启动时,它会倒计时。点击暂停会停止倒计时,取消会回到选择状态等。代码很大所以我放在这里

这个应用程序的问题是,当我点击“暂停”时,倒计时不会立即停止。它在停止之前仍然倒计时一个数字(例如,当在 5 处暂停时,它仍然倒计时到 4 并在 4 处停止)。

我试图找到错误,我猜错误仍然存​​在于components/time/index.js. 下面是文件

import React, { useState, useEffect, useRef } from "react";
import Hour from "./Hour";
import Minute from "./Minute";
import Second from "./Second";
import { setTimeout } from "timers";

export default function Index({ runningMode, selectMode }) {
  const [time, setTime] = useState({
    hour: 0,
    minute: 0,
    second: 0
  });
  // GET value from the button
  const getTime = name => value =>
    setTime(oldValue => ({ ...oldValue, [name]: value }));
  // COUNTDOWN setting
  const tickDown = () => {
    setTime(({ hour, minute, second }) => ({
      hour: minute === 0 ? (second === 0 ? hour - 1 : hour) : hour,
      minute: second === 0 ? (minute === 0 ? 59 : minute - 1) : minute,
      second: second === 0 ? 59 : second - 1
    }));
  };
  // Bug might be start here
  // All console.log() below for the purpose of debug
  const countDownRef = useRef();
  useEffect(() => {
    if (runningMode && time.hour >= 0) {
      countDownRef.current = setTimeout(tickDown, 2000);
      console.log("runningMode true");
    }
    if (!runningMode || time.hour < 0) {
      clearTimeout(countDownRef.current);
      console.log("runningMode wrong");
    }
    console.log("inside useEffect() ");
    console.log(countDownRef.current);
    console.log(time.second);
  }, [runningMode, time]);

  return (
    <React.Fragment>
      <Hour
        setHour={getTime("hour")}
        selectMode={selectMode}
        time={time.hour}
      />
      <Minute
        setMinute={getTime("minute")}
        selectMode={selectMode}
        time={time.minute}
      />
      <Second
        setSecond={getTime("second")}
        selectMode={selectMode}
        time={time.second}
      />
    </React.Fragment>
  );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

这段代码在这部分表现得很奇怪useEffect(),我猜这是错误的根源。奇怪的第一件事是setTimeout()那里返回的不是整数,而是一个相似的对象 - 根据这个
我尝试的另一件事是更改setTimeout()setInterval(). setInterval()在这种情况下,返回一个整数 - 也反对文档,因为它应该与setTimeout(). 更不用说使用setInterval()使我们无法停止倒计时工作 - 按钮不起作用

这段代码中的第二个奇怪的事情是clearTimeout()第一次调用时不起作用,然后下次调用。我试图跟踪执行的进度,当点击暂停时,它确实通过了clearTimeout()并且没有通过setTimeout(),但是超时并没有停止。我猜当点击暂停时传递给它的 timeoutID 会改变,但是当我注销该 ID 时它根本没有改变。

所以我被困在这里。猜猜它可以使用async/await解决,但我想知道为什么上面的这种方法会给出奇怪的结果。我还想知道如何修复这些错误以使应用程序按预期工作。谢谢

标签: reactjsuse-effect

解决方案


推荐阅读