4
头图

快来加入我们吧!

"小和山的菜鸟们",为前端开发者提供技术相关资讯以及系列基础文章。为更好的用户体验,请您移至我们官网小和山的菜鸟们 ( https://xhs-rookies.com/ ) 进行学习,及时获取最新文章。

"Code tailor" ,如果您对我们文章感兴趣、或是想提一些建议,微信关注 “小和山的菜鸟们” 公众号,与我们取的联系,您也可以在微信上观看我们的文章。每一个建议或是赞同都是对我们极大的鼓励!

前言

这篇文章,我们主要目的是了解一下 useRefs 的使用.

useRefs

定义

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

const refContainer = useRef(initialValue)

我们都知道,React 已经提供了一个 API createRef,它的作用同样也是创建一个 ref,那么这个 useRefs Hook 出来的意义是什么呢?它们之间又有什么区别呢?

useRef 的特性

useRef 一个很重要的特性就是:useref 返回的 ref 对象是可变的。正如官网文档中所说,它像一个变量,像可以保存一个可变值的“盒子”。

我们已经知道的 createRef 返回的 ref 对象在每次渲染时都会返回一个新的引用,而 useRef 则返回的是相同的引用 也正如定义中所说,返回的 ref 对象在组件的整个生命周期内保持不变。这也是为什么 useRef 可以在其 .current 属性中保存一个可变值的重要原因。

可能这比较难以理解,那我们用一个例子来理解一下:

function about() {
  const [count, addCount] = useState(0)
  const refForUseRef = useRef()
  const refForCreateRef = createRef()

  if (!refForUseRef.current) {
    // 如果不存在则赋值
    refForUseRef.current = count
  }
  if (!refForCreateRef.current) {
    refForCreateRef.current = count
  }

  return (
    <>
      <div>现在count的值为:{count}</div>
      <div>refForUseRef的值为:{refForUseRef.current}</div>
      <div>refForCreateRef的值为:{refForCreateRef.current}</div>
      <button onClick={() => addCount((val) => val + 1)}>点击+1</button>
    </>
  )
}

看一下效果,就算组件重新渲染,由于 refForUseRef 的值一直存在,所以无法重新赋值,这就是为什么说,useRef 返回的对 ref 的引用是相同的,且在整个生命周期内保持不变。

useRefs-gif1.gif

useRef 在 Hook 中的作用

我们都知道,Hook 的出现,让我们可以在函数组件中就可以做到 Class 组件中的一些特性,我们需要注意一点,Class 组件中有一个概念叫实例变量,那么基于 Hook 的函数组件存在类似实例变量吗?

答案是肯定的,useRef Hook 不仅可以用于 DOM refs,他还有一个重要的作用,就是容纳一个任意值的类似 Class 的实例属性,这也是前面提到的关于它的特性。

我们还是用一个例子,来感受一下使用 useRef 的函数组件的魅力吧。

用例子感受 useRef

不使用 useRef 的函数组件

function about() {
  const [count, addCount] = useState(0)

  function handleAlertClick() {
    setTimeout(() => {
      alert('弹框的count值:' + count)
    }, 2000)
  }

  return (
    <div>
      <div>现在count的值为:{count}</div>
      <button onClick={() => addCount((val) => val + 1)}>点击+1</button>
      <button onClick={() => handleAlertClick()}>展示弹框</button>
    </div>
  )
}

观察这个例子的效果,我们可以发现,弹框里的 count 值是在点击展示弹框按钮时的值,并不是 count 的实时状态,这是为什么呢?

useRefs-gif2.gif

其实,当我们更新状态的时候,React 会重新渲染组件,每一次渲染都会拿到独立的 count 状态, 并重新渲染一个 handleAlertClick 函数. 每一个 handleAlertClick 里面都有它自己的 count 所以每次弹框展示的就是点击时的 count 值。

如何让弹框里的值实时展示 count 值呢?

这个时候就用到了我们一直在讨论的 useRef了,直接看例子:

function about() {
  const [count, addCount] = useState(0)
  const refForUseRef = useRef(count)

  useEffect(() => {
    refForUseRef.current = count
  })

  function handleAlertClick() {
    setTimeout(() => {
      alert('弹框的count值:' + refForUseRef.current)
    }, 2000)
  }

  return (
    <div>
      <div>现在count的值为:{count}</div>
      <div>refForUseRef的值为:{refForUseRef.current}</div>
      <button onClick={() => addCount((val) => val + 1)}>点击+1</button>
      <button onClick={() => handleAlertClick()}>展示弹框</button>
    </div>
  )
}

因为 useRef 每次都会返回同一个引用, 所以在 useEffect 中修改的时候 ,在 alert 中也会同时被修改. 这样子, 点击的时候就可以弹出实时的 count 了.

useRefs-gif3.gif

在这个例子中,count 就类似于 Class 组件中的实例变量,useRef 让我们在函数组件中完成一些 Class 组件的功能。

总结

通过这一篇文章,我们了解到了 React Hook 为我们带了的一个钩子 useRef ,它返回的 ref 对象在组件的整个生命周期保持不变,让我们在函数组件中,也可以像 Class 组件一样保存一些实例属性,为我们开发带来了许多可能性,除了这些新奇的功能,不要忘记 ref 开始获取 DOM 属性的功能,因为在 useRef 同样可以适用。

下节预告

在下节中,我们将为大家介绍 useCallBack ,敬请期待!


小和山的菜鸟们
377 声望2.1k 粉丝

每日进步的菜鸟,分享前端学习手册,和有心学习前端技术的小伙伴们互相探讨,一同成长。