【问题标题】:Timer/Counter for react component - value remains 0 after increasing it with setInterval()反应组件的计时器/计数器 - 使用 setInterval() 增加后值保持为 0
【发布时间】:2021-06-15 03:11:46
【问题描述】:
export default function Timer() {
   const [timer, setTimer] = useState(0)

   const checkTimer = () => {
     console.log(timer);
   }

   useEffect(() => {
      const timer = setInterval(() => {
        setTimer(prevCount => prevCount + 1);
      }, 1000);

      startProgram(); //This starts some other functions

      return () => {
        checkTimer();
        clearInterval(timer);
      }
   }, [])
}

上面是我的代码的简化版本和主要问题 - 我试图通过在 useEffect() 中设置一个间隔来增加timer 状态(仅一次)。但是,在checkTimer() 中,该值始终为 0,即使控制台语句每秒执行一次。我是 reactjs 新手,希望能得到一些帮助,因为这已经花费了我太多时间来修复。

【问题讨论】:

  • 尝试创建一个自定义挂钩,如useInterval,如this post 的演示所示。这个钩子会比处理setTimeout更好。

标签: javascript reactjs timer react-hooks counter


【解决方案1】:

checkTimer 向您显示timer 状态的初始值,因为陈旧关闭。这意味着在执行useEffect 时(即由于[] 作为依赖项而在组件挂载时一次),它注册了一个创建闭包的cleanup 函数围绕checkTimer 函数(以及它使用的所有内容,状态或道具值)。当这个闭包被创建时,timer state 的值是0。它会一直如此。

修复它的选项很少。

一个快速解决方案是使用useRef

const timer = useRef(0);

const checkTimer = () => {
  console.log(timer.current);
};

useEffect(() => {
  const id = setInterval(() => {
    timer.current++;
  }, 1000);

  return () => {
    checkTimer();
    clearInterval(id);
  };
}, []);

查看this related post 以查看更多解决此问题的代码示例。


编辑:

而且,如果您还想在 UI 上显示 timer,我们需要使用 state,因为我们知道“ref”数据不会在 UI 上更新。所以,方案二是使用setTimer的“updater”形式来读取checkTimer函数中的最新状态数据:

const [timer, setTimer] = useState(0);

const checkTimer = () => {
  let prevTimer = 0;
  setTimer((prev) => {
    prevTimer = prev; // HERE
    return prev; // Returning same value won't change state data and won't causes a re-render
  });
  console.log(prevTimer);
};

useEffect(() => {
  const id = setInterval(() => {
    setTimer((prev) => prev + 1);
  }, 1000);

  return () => {
    checkTimer();
    clearInterval(id);
  };
}, []);

【讨论】:

  • 非常感谢!这很有效,终于在我的脑海中变得有意义
  • 使用此解决方案要记住一件事:如果您在 UI 的某处显示 timer 状态值,它不会更新。因为useRef 不参与重新渲染。但是如果你只是将它用于“计数器”,这很好。
  • 我只用作计数器,谢谢!出于好奇,它会用我上面发布的原始代码在 UI 上更新吗?如果我想实现两者(计算当前值并显示它),将两者结合起来是可接受的解决方案还是有更好的方法?另外,如果需要太多时间来解释,请随时不要进入。我刚刚进入 React,我最终会自己到达那里,只是这个问题花了我几个小时,我无法避免再寻求帮助:D
  • 查看我的编辑。当我们回到状态数据时,选项 2 也将更新 UI。还有另一个选项 3,它使用“计时器”作为 ref 变量和状态中的布尔标志来强制渲染。只需更改该布尔状态值,UI 也会显示来自“ref”的更新值。
  • 如果你结合两种方式:计时器的“ref”和“state”。您只需要注意无论何时都更新两者。 (如果我们忘记更新两者,我觉得这很麻烦。)
猜你喜欢
  • 1970-01-01
  • 2015-01-11
  • 1970-01-01
  • 2020-04-15
  • 1970-01-01
  • 2020-05-08
  • 2020-11-14
  • 2020-05-02
  • 1970-01-01
相关资源
最近更新 更多