首页 > 解决方案 > setInterval 和 React 钩子会产生意想不到的结果

问题描述

我在使用 create-react 搭建的应用程序中定义了以下组件:

import React, { useState } from 'react';

const Play = props => {
  const [currentSecond, setCurrentSecond] = useState(1);
  let timer;
  const setTimer = () => {
    timer = setInterval(() => {
      if (currentSecond < props.secondsPerRep) {
        setCurrentSecond(() => currentSecond + 1);
      }
    }, 1000);
  }
  setTimer();
  return (
    <div>
      <div>
        <p>{currentSecond}</p>
      </div>

    </div>
  );
}

export default Play;

并且currentSecond每秒更新一次,直到它遇到props.secondsPerRep但是如果我尝试setInterval从点击处理程序启动:

import React, { useState } from 'react';

const Play = props => {
  const [currentSecond, setCurrentSecond] = useState(1);
  let timer;
  const setTimer = () => {
    timer = setInterval(() => {
      if (currentSecond < props.secondsPerRep) {
        setCurrentSecond(() => currentSecond + 1);
      }
    }, 1000);
  }

  return (
    <div>
      <div>
        <button onClick={setTimer}>Start</button>
        <p>{currentSecond}</p>
      </div>

    </div>
  );
}

export default Play;

然后currentSecondsetInterval回调内总是返回初始值,即1。

任何帮助都非常感谢!

标签: reactjsreact-hooks

解决方案


您的问题是这条线setCurrentSecond(() => currentSecond + 1);,因为您只调用setTimer一次,您的间隔将始终在初始状态currentSecond为 1 时关闭。

幸运的是,您可以通过传递给setCurrentSecondlike的函数中的 args 访问实际的当前状态来轻松解决这个问题setCurrentSecond(actualCurrentSecond => actualCurrentSecond + 1)

此外,您要非常小心地在功能组件主体中任意定义间隔,因为它们不会被正确清除,就像如果您再次单击按钮,它将开始另一个间隔而不清除前一个间隔.

我建议您查看这篇博文,因为它会回答您对间隔 + 挂钩的任何问题:https ://overreacted.io/making-setinterval-declarative-with-react-hooks/


推荐阅读