Skip to content

useRef函数

使用useRef可以直接操作一个改变值后不需要渲染的值。

1. 使用useRef

useRef返回的是一个对象而不是数组:

jsx
import { useRef } from 'react'

function App() {
  const num = useRef(0)
  const clickHandler = () => {
    // 对普通变量也提供记忆功能,不会一直从0开始
    num.current = num.current + 1
    console.log(num.current)
  }
  return (
    <div>
      hello App
      <div>
        <button onClick={clickHandler}>点击添加</button>
      </div>
      <div>
        {num.current}
      </div>
    </div>
  )
}

export default App

运行结果,会发现num的值已经到4,但是jsx片段并没有重新渲染:
Alt text

2. 使用useRef场景

jsx
import { useRef, useState } from 'react'

function App() {
  const num = useRef(0)
  const [stateVariable, setStateVariable] = useState(0)
  // 如果不适用useRef, 各自的作用域将会清理不了timer
  let timer = null
  const clickHandler = () => {
    setStateVariable(stateVariable + 1)
    clearInterval(timer)
    timer = setInterval(() => {
      num.current = num.current + 1
      console.log(num.current)
    }, 1000)
  }
  return (
    <div>
      hello App
      <div>
        <button onClick={clickHandler}>点击添加</button>
      </div>
      <div>
        {num.current}, {stateVariable}
      </div>
    </div>
  )
}

export default App

运行效果:
Alt text

3. useRef和useState的区别

refstate
useRef(initValue)返回useState(initValue)返回state变量的当前值和一个state设置函数([value, setValue])
更改时不会触发重新渲染更改时触发重新渲染。
可变--你可以在渲染过程之外修改和更新current的值"不可变"--你必须使用state设置函数来修改state变量,从而排队重新渲染。
你不应该在渲染期间读取或写入current值。你可以随时读取state设置。但是每次渲染都有自己不变的state快照。

4. 使用ref操作DOM

由于React会自动处理更新DOM以匹配你的渲染输出,因此你在组件中通常不需要操作DOM。但是有时你可能需要访问由React管理的DOM元素。例如让一个节点获得焦点、滚动到它或测量它的尺寸和位置。

jsx
import { useRef, useState } from 'react'

function App() {
  const [num, setNum] = useState(0)
  const myRef = useRef(null)
  const clickHandler = () => {
    setNum(num+1)
    myRef.current.style.backgroundColor = 'red'
  }
  return (
    <div>
      hello App
      <div>
        <button onClick={clickHandler}>点击添加</button>
      </div>
      // 固定写法:ref={xxx}
      <div ref={myRef}>
        {num}
      </div>
    </div>
  )
}

export default App

运行结果:
Alt text 如果需要在jsx片段中使用ref:

jsx
import {  useState } from 'react'

function App() {
  const [dataList, setDataList] = useState([
    {id:1, name:'test'},
    {id:2, name:'jack'},
    {id:3, name:'zhangshan'},
  ])

  return (
    <div>
      hello App
      <ul>
        {dataList.map((item) => (
          <li key={item.id} ref={(myRef)=>{myRef.style.backgroundColor='blue'}}>{item.name}</li>
        ))}
      </ul>
    </div>
  )
}

export default App

运行效果:
Alt text

4. 使用forwardRef转发

当组件添加ref属性的时候,需要forwardRef进行转发,forwardRef让您的组件通过ref向父组件公开DOM节点。

jsx
import { useRef, forwardRef } from 'react'

const MyInput = forwardRef(function MyInput(props, ref) {
  return (
    <input type="text" ref={ref} />
  )
})

function App() {
  const myRef = useRef(null)
  const handleClick = ()=>{
    myRef.current.focus()
    myRef.current.style.background = 'red'
  }
  return (
    <div>
      <div>
        <button onClick={handleClick}>点击</button>
      </div>
      <MyInput ref={myRef} />
    </div>
  )
}

export default App

运行效果:
Alt text 可以看到ref转发到子组件MyInput里面的input组件上面,input组件就可以暴露到父组件上面,被外面进行操作。