React-函数组件中的定时器

文章目录

  • 一、函数组件中的定时器
    • 1.了解定时器:
    • 2.清理函数组件中的定时器
    • 3.使用定时器展示倒计时

一、函数组件中的定时器

useEffect使用完全指南:https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/

1.了解定时器:

  1. 先点击【延迟获取 count 值】按钮
  2. 立即点击【+1】按钮 3 次

问题:定时器打印的 count 值为多少?

提示:点击【延迟获取 count 值】按钮,创建定时器时,当前的状态值 count 是多少(组件是第几次更新)?

const App = () => {
  const [count, setCount] = useState(0)
  
  // 3 秒后,获取 count 值
  const getCount = () => {
    setTimeout(() => {
      console.log(count)
    }, 3000)
  }

  // 计数器 +1
  const handleClick = () => {
    setCount(count + 1)
  }
  
  return (
    <div>
      <button onClick={handleClick}>+1</button>
      <button onClick={getCount}>延迟获取 count 值</button>
      <h1>计数器:{count}</h1>
    </div>
  )
}

2.清理函数组件中的定时器

问题:这种方式能正确清理定时器吗?

操作过程如下:

  1. 先点击【+1】按钮 1 次,让组件重新更新
  2. 再点击【清理定时器】按钮

分析该问题的出发点:clearIntervaltimerIduseEffect 中的 timerId 是不是同一个?(提示:可以通过打印的方式,查看两处 timerId 的值)

const App = () => {
  const [count, setCount] = useState(0)
  let timerId = -1

  useEffect(() => {
    timerId = setInterval(() => {
      console.log('interval')
    }, 1000)
  }, [])

  const clear = () => {
    clearInterval(timerId)
  }

  const handleClick = () => {
    setCount(count + 1)
  }

  return (
    <div>
      <button onClick={handleClick}>+1</button>
      <button onClick={clear}>清理定时器</button>
      <h1>计数器:{count}</h1>
    </div>
  )
}

因此,要想在组件更新后清理定时器,就需要让两处的 timerId 值是同一个,也就是要保持 timerId 的值在组件更新期间保持不变。此时,就用到:useRef Hook 了。

// 创建 ref 对象
const timerRef = useRef(-1)

useEffect(() => {
  // 将定时器id存储到 ref 对象中
  timerRef.current = setInterval(() => {
    console.log('interval')
  }, 1000)
}, [])

const clear = () => {
  // 从 ref 对象中拿到之前存储的定时器id
  clearInterval(timerRef.current)
}

// 说明:两个地方拿到的 timerRef.current 是同一个对象!

3.使用定时器展示倒计时

对于倒计时的定时器来说,只需要在组件创建时,开启一次即可。为了做到这一点,可以通过 useEffect(() => {}, []) 来实现

注意:此处的关键点是依赖项参数为:[](空数组)。因此,不能在 effect 回调函数中,依赖外部的数据

但是,页面中的计数器数值又要更新,因此就会有一个新的问题:

如何在不依赖于外部数据的情况下,在 effect 回调中,更新状态?

答:使用回调函数形式的setState来更新状态

const [count, setCount] = useState(0)

// 语法一:
setCount(count + 1)

// 语法二:回调形式的更新状态
setCount(prevCount => prevCount + 1)

对比以上两种语法的不同点:

// 语法一: 依赖外部数据,需要通过 useEffect 的第二个参数指定
useEffect(() => {
  setCount(count + 1)
}, [count])

// 语法二: 不依赖于外部数据,不需要指定 useEffect 的依赖
useEffect(() => {
  setCount(prevCount => prevCount + 1)
}, [])

你可能感兴趣的:(React,react.js,javascript,前端,react,开发语言)