React-函数组件中的定时器

一、函数组件中的定时器

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)
}, [])
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
可以通过 useEffect 钩子函数来实现计时器的启动和销毁。 具体实现如下: ```jsx import React, { useState, useEffect } from 'react'; function Timer({ seconds }) { const [count, setCount] = useState(seconds); useEffect(() => { const interval = setInterval(() => { setCount(count => count - 1); }, 1000); return () => clearInterval(interval); }, []); useEffect(() => { if (count <= 0) { clearInterval(interval); } }, [count]); return <div>{count}</div>; } export default Timer; ``` 在上面的代码,我们定义了一个 Timer 组件,它接受一个 seconds 参数表示计时器的初始时间。 在组件的状态,我们使用 useState 钩子来定义一个 count 变量,用于记录当前计时器的剩余时间。 在 useEffect 钩子,我们使用 setInterval 函数来每秒更新一次 count 变量的值,并返回一个清除计时器的函数,以便在组件销毁时清除计时器。 我们还定义了一个第二个 useEffect 钩子,用于判断计时器是否已经结束,如果结束则清除计时器。 最后,在组件的返回值,我们将 count 变量渲染到页面用于展示当前剩余时间。 使用方式如下: ```jsx import React from 'react'; import Timer from './Timer'; function App() { return ( <div> <Timer seconds={10} /> </div> ); } export default App; ``` 在上面的代码,我们将 Timer 组件引入到 App 组件,并传入了一个 seconds 参数,表示计时器的初始时间为 10 秒。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄昏终结者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值