【问题标题】:useEffect stops working after the first time useState's set becomes stale within a timeruseEffect 在第一次 useState 的集合在计时器内过时后停止工作
【发布时间】:2021-09-27 12:42:56
【问题描述】:

我本质上想要一个计时器来不断更新显示的计算时间。如果我运行 setTimeout 的速度比预期的时间快,则计算会产生一个新的时间数字(840 毫秒对 1000 毫秒),循环将永远结束。如何使用 React Hooks 完成这项工作?不寻找将其保持在 1000 毫秒的答案。我正在尝试查找我对 useState 和 useEffect 的使用是否不正确,或者是否有我没有想到的更好的钩子。

import { useEffect, useState } from "react";
function App() {
  const [display, setDisplay] = useState("0");
  useEffect(() => {
    console.log("display", display);
    function calculateTime() {
      console.log('timer', Date.now() - 1626712121266);
      return Date.now() - 1626712121266;
    }
    let timeoutId: NodeJS.Timeout;
    timeoutId = setTimeout(() => {
      console.log("setTimeout")
      setDisplay(displayTime(calculateTime()));
    }, 840);
    return () => {
      clearTimeout(timeoutId);
    }
  }, [display]);
  return (
    <>
      {display}
    </>
  );
}
function displayTime(milliseconds: number) {
  const seconds = Math.floor(milliseconds / 1000 % 60);
  const displaySeconds = (seconds < 10) ? '0' + seconds : seconds;
  let displayString = "" + displaySeconds;
  console.log('displayString', displayString)
  return displayString;
}
export default App;

刷新后的控制台结果。请注意,一旦几秒钟保持不变,useEffect 就会停止被调用。

我是如何创建这个测试的:

  1. yarn create react-app test-timer --template typescript

  2. 将 App() 函数替换为此处显示的内容。

【问题讨论】:

    标签: reactjs typescript settimeout create-react-app use-effect


    【解决方案1】:

    使用 setInterval 作为计时函数将 useState 转换为 useReducer 就可以了。 useReducer 对我来说仍然是一个神奇的黑匣子,但它现在可以正常工作。希望解释为什么会发生这种情况。

    import { useEffect, useReducer } from "react";
    function App() {
      function reducer(state: any, action: any): any {
        if (action.type === 'displayUpdate') {
          const display = displayTime(Date.now() - 1626712121266);
          return {
            display: display,
          };
        }
      }
    
      const [state, dispatch] = useReducer(reducer, { display: "0" });
    
      useEffect(() => {
        console.log("useEffect");
    
        let intervalId = setInterval(() => {
          console.log("setInterval")
          dispatch({type: 'displayUpdate'});
        }, 500);
    
        return () => {
          console.log('useEffect return')
          clearInterval(intervalId);
        }
      }, []);
      return (
        <>
          {state.display}
        </>
      );
    }
    function displayTime(milliseconds: number) {
      const seconds = Math.floor(milliseconds / 1000 % 60);
      const displaySeconds = (seconds < 10) ? '0' + seconds : seconds;
      let displayString = "" + displaySeconds;
      console.log('displayString', displayString)
      return displayString;
    }
    export default App;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-16
      • 2021-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多