Skip to main content

hooks使用之useRef

useState ---> 构建组件状态 当状态变更的时候 组件必定重新渲染

useRef: 构建一个状态出来, 但是这个状态是直接脱离react控制的, 他的变化也不会造成重新渲染, 同时状态还不会因为组件的重新渲染而被初始化


import {useState, useCallback, useRef} from 'react'
export default function Ticker() {
const [timeCount, setTimeCount] = useState(60)

const timerIdRef = useRef(null)
// useRef会返回一个对象 对象里面有个current属性
// ref 是可读可写的

const startTick = useCallback(() => {
if(timerIdRef.current) return
timerIdRef.current = setInterval(() => {
setTimeCount(prev => prev - 1)
}, 1000)
}, [])

const stopTick = useCallback(() => {
if (timerIdRef.current) clearInterval(timerIdRef.current)
}, [])


// 有且只有一个根组件 <></> --> 是一个语法糖 React.Fragment
return (
<>
<button onClick={startTick}>start</button>
<button onClick={stopTick}>stop</button>
<span>{ timeCount }</span>
</>
)
}

处理真实dom

export default function TestInput() {
// 需求 当点击 clickme 的时候 输入框聚焦

const [inputElement, setInputElement] = useState(null)

useEffect(() => {
// 这个真实dom 和react 有没有任何关系
const inputEl = document.getElementsByClassName("input-example")[0]
setInputElement(inputEl)
})

const handlerClick = useCallback(() => {
inputElement.focus()
}, [])
return (
<div>
<input type="text" className="input-example" />
<button onClick={handlerClick}>click me</button>
</div>
)
}

使用useRef的实现

export default function TestInput() {
const inputElementRef = useRef(null)

// useEffect(() => {
// // 这个真实dom 和react 有没有任何关系
// inputElementRef = document.getElementsByClassName("input-example")[0]
// })

const handlerClick = useCallback(() => {
inputElement.current.focus()
}, [])


return (
<div>
{/* 这种ref 使用了useEffect 去帮你获取dom 并且赋值 */}
<input ref={inputElementRef} type="text" className="input-example" />
{/* */}
{/* <input type="text" className="input-example" /> */}
<button onClick={handlerClick}>click me</button>
</div>
)
}

Question:

  1. 既然我可以通过document.xx.getElementById直接拿到真实dom, 那么useRef存在的意义是什么?

    • useRef不是不仅为了真实dom服务 构建一个状态出来, 但是这个状态是直接脱离react控制的, 他的变化也不会造成重新渲染, 同时状态还不会因为组件的重新渲染而被初始化
  2. 如果不使用useRef去处理真实dom, 会出现什么问题?

    • 不用ref就需要构建状态, 而使用状态会造成没必要的重新渲染, 用全局变量去控制, 又会造成闭包问题