[react] hooks基础 => useRef ===

目录

使用 useRef 操作DOM

useRef-在多次渲染之间共享数据

自定义hooks-封装倒计时-需求-验证码

自定义hooks-封装倒计时-需求-404页面3秒跳转

自定义hooks-封装倒计时-提炼hooks


使用 useRef 操作DOM

使用场景:在 React 中进行 DOM 操作时,用来获取 DOM

作用:返回一个带有 current 属性的可变对象,通过该对象就可以进行 DOM 操作了。

const inputRef = useRef(null) 

解释:

  • 参数:在获取 DOM 时,一般都设置为 null

  • 返回值:包含 current 属性的对象。

  • 注意:只要在 React 中进行 DOM 操作,都可以通过 useRef Hook 来获取 DOM(比如,获取 DOM 的宽高等)。

  • 注意:useRef不仅仅可以用于操作DOM,还可以操作组件

示例代码 

// 第一步,引入useRef
import { useRef } from 'react'
import reactDom from 'react-dom'

export default function App () {
  // 第二步,调用useRef,并设置一个空的初始值,得到引入对象
  const inpRef = useRef(null)
  const changeInp = () => {
    //   第四部,通过引入对象.current属性,获得元素或组件
    console.log(inpRef.current)
    inpRef.current.style.backgroundColor = 'red'
    inpRef.current.focus()
  }
  return (
        <div>
            {/* 第三步,把引入对象设置ref给任意元素或组件 */}
            <input ref={inpRef}></input>
            <button onClick={changeInp}>按钮</button>
        </div>
  )
}

reactDom.render(<App></App>, document.querySelector('#root'))

useRef-在多次渲染之间共享数据

问题导入

import React, { useEffect, useState } from 'react'
import ReactDom from 'react-dom'
export default function App () {
  const [count, setCount] = useState(0)
  let timeId = null
  console.log(timeId)
  useEffect(() => {
    timeId = setInterval(() => {
      setCount((count) => count + 1)
    }, 1000)
    console.log(timeId)
  }, [])

  const hClick = () => {
    console.log(timeId)
    clearInterval(timeId)
  }

  return (
    <div>
      count:{count}
      <button onClick={hClick}>点击停止定时器</button>
    </div>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

分析问题

setCount会导致组件重新渲染,而重新渲染时,会重复执行如下代码

let timeId = null

所以,无法保存timeId

解决方法 

将timeId保存在一个多次渲染也不会丢失的位置。

// 1. 导入 useRef
import React, { useRef } from 'react'

组件() {
  // 2. 调用useRef,
  const timeRef = useRef(null)
  // 3. 向引用的current中存入数据
  timeRef.current = 你需要在多次渲染之间共享的数据
}
import React, { useEffect, useRef, useState } from 'react'
import ReactDom from 'react-dom'
export default function App () {
  const [count, setCount] = useState(0)
  const timeRef = useRef(null)
  console.log(timeRef.current)
  useEffect(() => {
    timeRef.current = setInterval(() => {
      setCount((count) => count + 1)
    }, 1000)
    console.log(timeRef.current)
  }, [])

  const hClick = () => {
    console.log(timeRef.current)
    clearInterval(timeRef.current)
  }

  return (
    <div>
      count:{count}
      <button onClick={hClick}>点击停止定时器</button>
    </div>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

自定义hooks-封装倒计时-需求-验证码

import { useState, useEffect, useRef } from 'react'
import reactDom from 'react-dom'

function App () {
  const [flag, setFlag] = useState(false)
  const [count, setCount] = useState(0)
  const btnRef = useRef(null)

  // 组件销毁时,触发 componentWillUnmount,清除定时器
  useEffect(() => {
    return () => {
      clearInterval(btnRef.current)
      console.log('组件已毁,玉石俱焚')
    }
  }, [])

  // 监听count,如果为0,执行回调
  useEffect(() => {
    if (count === 0) {
      clearInterval(btnRef.current)
      setFlag(() => false)
    }
    console.log(count)
  }, [count])

  // 点击按钮执行事件
  const changeState = () => {
    // 1.初始化定时器
    setCount(5)
    // 2.按钮变为禁用
    setFlag(() => { return true })
    // 3.开启倒计时
    btnRef.current = setInterval(() => {
      setCount((count) => {
        return count - 1
      })
    }, 1000)
  }

  return (
    <div>
      <button disabled={flag} onClick={changeState} >
         {flag ? count + 's后重新获取' : '点击获取验证码'}
      </button>
    </div>
  )
}

export default function Box () {
  const [show, setShow] = useState(true)

  return (
   <div>
      {show && <App></App>}
    <button onClick={() => { setShow(false) }}>销毁</button>
   </div>
  )
}

reactDom.render(<Box></Box>, document.querySelector('#root'))

自定义hooks-封装倒计时-需求-404页面3秒跳转

import { useState, useEffect, useRef } from 'react'
import reactDom from 'react-dom'

export default function App () {
  // 设置初始值
  const [count, setCount] = useState(3)
  // 调用useRef,
  const timerRef = useRef(null)
  // 启动定时器
  useEffect(() => {
    timerRef.current = setInterval(() => {
      setCount((count) => count - 1)
    }, 1000)
  }, [])
  // 定时器到点后,清空并跳转
  useEffect(() => {
    if (count <= 0) {
      clearInterval(timerRef.current)
      location.href = 'http://www.baidu.com'
    }
  }, [count])
  // 手动点击,立即清空并跳转
  const jump = () => {
    clearInterval(timerRef.current)
    location.href = 'http://www.baidu.com'
  }

  return (
        <div>
            {count + '后跳转到百度'}
            <p>
              点击
              <span style={
   
   { color: 'blue', borderBottom: '1px solid blue', cursor: 'pointer' }} onClick={jump}>
                www.baidu.com
              </span>立即跳转
            </p>
        </div>
  )
}

reactDom.render(<App></App>, document.querySelector('#root'))

自定义hooks-封装倒计时-提炼hooks

import { useState, useEffect, useRef } from 'react'

export default function useTimer (init, callback) {
  const [count, setCount] = useState(init)
  const timerRef = useRef(null)

  const state = () => {
    // 每次调用从新赋予初始值
    setCount(init)
    timerRef.current = setInterval(() => {
      setCount((init) => init - 1)
    }, 1000)
  }

  //   组件销毁时清除定时器
  useEffect(() => {
    return () => {
      clearInterval(timerRef.current)
    }
  }, [])
  // 如果初始值小于0,清除定时器
  useEffect(() => {
    // 如果倒计时归0,清除定时器,调用函数
    if (count <= 0) {
      clearInterval(timerRef.current)
      callback()
    }
  }, [count])

  return { count, state }
}

模拟获取验证码 

import { useState } from 'react'
import reactDom from 'react-dom'
import useTimer from './useTimer'

function App () {
  const [flag, setFlag] = useState(false)
  const timer = useTimer(3, () => { setFlag(false) })
  // 点击按钮执行事件
  const changeState = () => {
    // 禁用按钮
    setFlag(true)
    // 调用函数,启动定时器
    timer.state()
  }

  return (
    <div>
      <button disabled={flag} onClick={changeState} >
         {flag ? timer.count + 's后重新获取' : '点击获取验证码'}
      </button>
    </div>
  )
}

export default function Box () {
  const [show, setShow] = useState(true)

  return (
   <div>
      {show && <App></App>}
    <button onClick={() => { setShow(false) }}>销毁</button>
   </div>
  )
}

reactDom.render(<Box></Box>, document.querySelector('#root'))

倒计时跳转页面

import reactDom from 'react-dom'
import { useEffect } from 'react'
import useTimer from './useTimer'

export default function App () {
  const { count, state } = useTimer(3, () => { location.href = 'http://www.baidu.com' })

  useEffect(() => {
    state()
  }, [])

  return (
        <div>{count} 后跳转到百度,或点击<a href="http://www.baidu.com">百度</a>跳转</div>
  )
}

reactDom.render(<App></App>, document.querySelector('#root'))

Guess you like

Origin blog.csdn.net/weixin_58726419/article/details/121305130