Timer/Counter 对于 React 组件 - 在使用 setInterval() 增加值后值保持为 0

Timer/Counter for react component - value remains 0 after increasing it with setInterval()

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 的新手,希望得到一些帮助,因为这已经花了我太多时间来修复。

checkTimer 向您显示 timer 状态的初始值,因为 过时的关闭 。这意味着在执行 useEffect 时(即 一旦在组件安装时由于 [] 作为依赖项 ),它注册了一个 cleanup 函数围绕 checkTimer 函数创建了一个闭包(以及它使用的所有内容,状态或道具值)。当创建此闭包时,timer 状态的值为 0。它将永远如此。

修复它的选项很少。

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

const timer = useRef(0);

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

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

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

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


编辑:

而且,如果您还想在 UI 处显示 timer,我们需要使用 state,因为我们知道“ref”数据不会在 UI 更新。所以,选项2是使用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);
  };
}, []);