Skip to content

React Hooks 系列 之 useRef

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传递的参数(initialValue)。返回的对象将在组件的整个生命周期内保持不变。

返回一个持久的对象

demo 代码
jsx
import { useEffect, useRef, useState } from 'react'

function Timer() {
  const [isRunning, setIsRunning] = useState(false)
  const count = useRef(0)
  const intervalRef = useRef(null)

  useEffect(() => {
    return () => {
      if (intervalRef.current) {
        clearInterval(intervalRef.current)
      }
    }
  }, [])

  const startTimer = () => {
    if (!isRunning) {
      setIsRunning(true)
      intervalRef.current = setInterval(() => {
        count.current += 1
        console.log(`Timer has run ${count.current} times.`)
      }, 1000)
    }
  }

  const stopTimer = () => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current)
      setIsRunning(false)
    }
  }

  return (
    <Card title="案例 demo">
      <p>
        Check the console to see the timer count:
        {count.current}
      </p>
      <Space>
        <Button onClick={startTimer} type="primary" disabled={isRunning}>
          开始
        </Button>
        <Button onClick={stopTimer} disabled={!isRunning}>
          停止
        </Button>
      </Space>
    </Card>
  )
}

export default Timer

上述的 demo 展示了 useRef 的以下特性:

  1. 持久性useRef 返回的 ref 对象在组件的整个生命周期内都是持久的。

  2. 不会引起组件重新渲染:与 useState 不同,修改 useRef.current 属性不会引起组件重新渲染。在 demo 中,即使我们增加了 count.current 的值,组件也没有重新渲染。

与 DOM 交互

demo 代码
jsx
import { useRef } from 'react'

function TextInputWithFocus() {
  const inputEl = useRef(null)
  const onButtonClick = () => {
    inputEl.current.focus()
  }
  return (
    <Card title="案例 demo">
      <Space>
        <Input ref={inputEl} placeholder="click button" />
        <Button onClick={onButtonClick} type="primary">
          Focus the input
        </Button>
      </Space>
    </Card>
  )
}

export default TextInputWithFocus

这个 demo 主要展示了 useRef 如何在 React 中用于直接与 DOM 元素交互。

保存上一次的值

demo 代码
jsx
import { useEffect, useRef, useState } from 'react'

function PreviousValueComponent() {
  const [count, setCount] = useState(0)
  const prevCountRef = useRef()

  useEffect(() => {
    prevCountRef.current = count
  }, [count])

  return (
    <Card title="案例 demo">
      <p>
        Current count:
        {count}
      </p>
      <p>
        Previous count:
        {prevCountRef.current}
      </p>
      <Button onClick={() => setCount(count + 1)} type="primary">
        Increment
      </Button>
    </Card>
  )
}

export default PreviousValueComponent

这个 demo 主要展示了 useRef 如何在 React 中用于跟踪上一次的值。