setInterval 启动和停止行为

setInterval start and stop behavior

我正在创建一个秒表,它有一个按钮来开始和停止时间,但我在设置间隔行为方面遇到了问题。

当在 React 的功能组件级别声明时,它将 运行 一旦挂载。
示例:

const Timer = () => {
    const timer = setInterval(() => console.log('running'), 1000)
}

当我在函数中声明它时,它不会运行直到函数被调用,但我无法让它停止。

const Timer = () => {
    const [start, setStart] = useState(false)

    const startStopTimer = () => {
        const timer = setInterval(() => console.log('running'), 1000)
    }

    return (<Button 
                onClick={() => {
                   setStarted(!start)
                   startStopTimer()
                }
             > Start/Stop </Button>)
}

然后我尝试在函数中添加 clearInterval() 并在 start === false 时有条件地调用它。在这个实现中,第一次点击按钮什么都不做。第二次点击启动计时器,但无法停止。

const Timer = () => {
    const [start, setStart] = useState(false)

    const startStopTimer = () => {
        let timer = setInterval(() => console.log('running'), 1000)
        if (!started) clearInterval(timer)
    }

    return (<Button 
                onClick={() => {
                   setStarted(!start)
                   startStopTimer()
                }
             > Start/Stop </Button>)
}

再见,我建议你这样修改你的代码:

const Timer = () => {
    //const [start, setStart] = useState(false) do not use state for scripting reasons
    let timer = null;

    const startStopTimer = () => {
        if(!timer) timer = setInterval(() => console.log('running'), 1000)
        else {
           clearInterval(timer)
           timer = null
        } 
    }

    return (<Button 
                onClick={() => {
                   //setStarted(!start)
                   startStopTimer()
                }
             > Start/Stop </Button>)
}

说明:timer 应该定义在 startStopTimer 之外,否则,每次启动 startStopTimer 时,都会创建一个新的 timer

好的,这很简单,但现在是重要的部分:我强烈建议您不要出于脚本原因使用 React 状态。反应状态应该只用于渲染原因。为什么?因为钩子是异步的,如果你在使用 setStart 后立即读取 start,你将读取一个旧值。

timer 变量是本地变量,每次调用 sartStopTimer() 时仅在 sartStopTimer() 范围内,它会生成新的 timer 并且在清除超时时,您只会清除最近生成的一个不是以前的 timer

let timer;
const startStopTimer = () => {
        timer = setInterval(() => console.log('running'), 1000)
        if (!started) clearInterval(timer)
    }

创建 timer 全局变量。

这应该可以帮助您入门。

试试这个:

const Timer = () => {
    const [timerId, setTimerId] = useState(null)
        
    function startStopTimer(){
      if (timerId) {
        clearInterval(timerId)
        setTimerId(null)
      } else {
        setTimerId(setInterval(() => console.log('hello'), 1000))
      }
    }
    return <button onClick={startStopTimer}> Start/Stop </button>
}

顺便说一句,不需要使用状态。如果你不需要保持定时器状态,你当然可以使用普通变量。