• 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>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    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>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    因此,要想在组件更新后清理定时器,就需要让两处的 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 是同一个对象!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

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

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

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

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

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

    const [count, setCount] = useState(0)
    
    // 语法一:
    setCount(count + 1)
    
    // 语法二:回调形式的更新状态
    setCount(prevCount => prevCount + 1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    // 语法一: 依赖外部数据,需要通过 useEffect 的第二个参数指定
    useEffect(() => {
      setCount(count + 1)
    }, [count])
    
    // 语法二: 不依赖于外部数据,不需要指定 useEffect 的依赖
    useEffect(() => {
      setCount(prevCount => prevCount + 1)
    }, [])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    Try llama2 in NUC (by quqi99)
    三分钟搭建一个自己的 ChatGPT (从开发到上线)
    网络安全知识渗透测试
    交换机与路由技术-14-三层交换机配置
    OPENCV实现人类识别(包括眼睛、鼻子、嘴巴)
    【Leetcode】881. Boats to Save People(配数学证明)
    React中Immutable的使用
    逆旅热闹如花盛放
    Leetcode力扣题解 - 30.串联所有单词的子串
    MYSQL:B树和B+树存储索引比较
  • 原文地址:https://blog.csdn.net/m0_62181310/article/details/126823585