【问题标题】:React useRef() with setInterval() in useCallBack() function not clearing upon clearInterval()在 useCallBack() 函数中将 useRef() 与 setInterval() 反应,在 clearInterval() 时未清除
【发布时间】:2021-11-09 00:30:36
【问题描述】:

我有这个秒表代码,它在屏幕上显示经过的时间。 (反应组件)

一切正常,但调用“clearInterval(increment.current)”(在 React 中使用 useRef() 作为范围)似乎并没有真正“停止”间隔。它不断在控制台中记录“已触发”(每秒)-我不明白为什么当 currentActivityOn === false 时仍会在 clearInterval() 之后调用它。 (而且如果定时器被触发多次,每秒触发不止一次。)

有什么建议吗?

import React, { useEffect, useRef, useCallback, useContext } from 'react'
import Container from '@material-ui/core/Container'
import Typography from '@material-ui/core/Typography'

import useLocalStorage from '../../hooks/useLocalStorage'
import { FlowTimeContext } from '../../services/flow/flow-time.context'
import { useStyles } from './grid-stopwatch.styles'

export default function GridStopwatch() {
  const classes = useStyles()

  const { currentActivityOn } = useContext(FlowTimeContext)

  const [timerStartTime, setTimerStartTime] = useLocalStorage('timerStartTime', '')
  const [timer, setTimer] = useLocalStorage('timer', 0)
  const increment = useRef(null)

  const handleTimerRun = useCallback(() => {
    increment.current = setInterval(() => {
      if(timerStartTime !== ''){
        const new_timer = ((Math.floor(new Date().getTime() / 1000)) - timerStartTime)
        setTimer(new_timer)
      } else {
        console.log("Triggered") // Why is this being called continually?
      }
    }, 1000)
  }, [setTimer, timerStartTime])

  const handleReset = useCallback(() => {
    clearInterval(increment.current)
    setTimer(0)
    setTimerStartTime('')
  }, [setTimer, setTimerStartTime])

  const handleStart = useCallback(() => {
    if(timerStartTime === ''){
      var start = Math.floor(new Date().getTime() / 1000)
      setTimerStartTime(start)
    }
  }, [timerStartTime, setTimerStartTime])

  const formatTime = () => {
    const getSeconds = `0${timer % 60}`.slice(-2)
    const minutes = `${Math.floor(timer / 60)}`
    const getMinutes = `0${minutes % 60}`.slice(-2)
    const getHours = `0${Math.floor(timer / 3600)}`.slice(-2)

    return `${getHours}h : ${getMinutes}m : ${getSeconds}s`
  }

  useEffect(() => {
    if(currentActivityOn === true){
      handleStart()
      handleTimerRun()
    } else {
      handleReset()
    }
  }, [currentActivityOn, handleStart, handleReset, handleTimerRun])

  return (
    <Container maxWidth='xl' className={classes.container}>
      {currentActivityOn && (
        <Typography variant='subtitle2' gutterBottom>
          Current Activity Duration: {formatTime()}
        </Typography>
      )}
    </Container>
  )
}

【问题讨论】:

  • 您可能应该添加 increment 作为 handleTimeRun useCallback 的依赖项。
  • 我已将增量添加为依赖项,但这没有任何区别。 (我想既然它是一个 useRef,代码 linting 并没有抱怨没有它;但它也没有抱怨它。)

标签: reactjs


【解决方案1】:

所以在这种情况下 useEffect 会被触发两次。因此,handleTimerRun 被调用了两次,似乎每次都启动了一个从未清除过的额外间隔。

  const handleTimerRun = useCallback(() => {
    if(timerStartTime !== ''){
      increment.current = setInterval(() => {
        const new_timer = ((Math.floor(new Date().getTime() / 1000)) - timerStartTime)
        setTimer(new_timer)
      }, 1000)
    }
  }, [setTimer, timerStartTime, increment])

现在我可以通过在开始间隔之前移动条件来解决这个问题,所以它只开始一次。这似乎解决了我的问题,但它是一种解决方法,而不是真正理解“如何”开始分配相同 ID 的额外间隔。 (而且似乎无法“停止”)

如果能更清楚地说明这一点,我们当然会感激不尽。

似乎如果我控制台记录 increment.current,它会不断增加 - 而我认为这将是一个一致的 ID...? (是可变的,但在不发生突变时是一致的。)

【讨论】:

    猜你喜欢
    • 2021-12-15
    • 2016-03-14
    • 2020-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    相关资源
    最近更新 更多