javascript - setInterval + React hooks 导致组件内多次更新

标签 javascript reactjs react-hooks setinterval

我正在构建一个秒表 UI,以秒为单位显示时间。单击按钮,计时器将开始向上计数,并在再次单击时停止。用户应该能够再次启动它。

我遇到的问题是,我可以让 setInterval 正常工作,但是一旦包含 setTime Hook ,组件就会更新以在 UI 中呈现时间,但setInterval 实例被多次调用。这会导致奇怪的渲染行为。

const Timer = () => {
    const [time, setTime] = useState(0)
    let timer

    const startStopTimer = () => {
        if (!timer) timer = setInterval(() => setTime(time++), 1000)
        else {
           clearInterval(timer)
           timer = null
        }
    }

    return (
            <div>
               <p>Time: {time} seconds</p>
               <Button 
                   onClick={() => {
                      startStopTimer()
                   }
               > Start/Stop </Button>
            </div>
           )
}

示例行为是:

  1. 用户点击“开始/停止”
  2. 计时器从 0 开始向上计数
  3. 用户点击“开始/停止”
  4. 计时器立即停止
  5. 用户点击“开始/停止”
  6. 计时器从上次停止的地方继续

最佳答案

这是 React hook 中过时闭包的典型示例,在调用 setTime 后,time 的 setInterval 值不会改变。更改您的代码:

setInterval(() => setTime(currentTime => currentTime + 1), 1000)

setTime 就像有类组件的 setState 一样,也接受一个回调函数,该函数将当前值作为第一个参数

此外,timer 变量在您的代码中毫无用处,因为每次重新渲染时它都将是未定义的,并且您将无法访问 setInterval 的返回值,因此它将重新初始化setInterval。要处理该使用 useRef,您可以将 setInterval 的返回值存储在 .current 中,在后续重新渲染后您将可以使用它,因此不需要更多重新初始化 setInterval ,您还可以使用 clearInterval

解决方案:

const {useState, useRef} = React;
const {render} = ReactDOM;

const Timer = () => {
  const [time, setTime] = useState(0);
  const timer = useRef(null);
  const startStopTimer = () => {
    if (!timer.current) {
      timer.current = setInterval(() => setTime(currentTime => currentTime + 1), 1000);
    } else {
      clearInterval(timer.current);
      timer.current = null;
    }
  };

  return (
    <div>
      <p>Time: {time} seconds</p>
      <button
        onClick={startStopTimer}
      >
        Start/Stop
      </button>
    </div>
  );
};

render(<Timer />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>

关于javascript - setInterval + React hooks 导致组件内多次更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63458425/

相关文章:

javascript - 只有在多个状态完成更新后才调用函数

javascript - React redux - componentDidMount 获取与操作

javascript - 使用 React Hooks 输入千位分隔符

reactjs - React-apollo 突变 writeQuery 不更新 ui

reactjs - 使用 i18next 时如何处理 ESLint react-hooks 'exhaustive-deps' 规则?

javascript - React 函数式组件真的比类组件更轻量级吗?

javascript - 用 express + webpack-dev-middleware/webpack-hot-middleware 替换 webpack-dev-server

javascript - 如何在javascript函数中添加html文件?

javascript - 我不知道如何从 DOM (JavaScript) 获取数字

javascript - 事件监听器甚至在 Chrome 上也无法工作?