为何不推荐在react组件中直接定义变量?探秘useRef的使用以及userRef与useState的区别

为何不推荐在react组件中直接定义变量?探秘useRef的使用以及userRef与useState的区别

前言

今天在写代码的时候遇到一个问题,我的一个组件需要维护一个不需要在页面中渲染的变量。那么我想,既然它不需要渲染,我直接用let变量新建一个不就可以了吗?

但是当我真正用这个let创建的变量时,才意识到大事不好,原来这么使用变量有一个大问题!

为什么要有hook

要说明问题是什么,我们需要先弄明白一件事情,我们使用函数式组件时我们怎么去render ?在我们使用类式组件时,rerender可能是简单的调用一次render方法,那对于函数式组件呢?函数式组件的render写在return语句中,很明显我们需要重新执行整个函数。

那么我在前言部分提到的问题就呼之欲出了:组件每次渲染更新都会使得变量变为初始值。也就是说我在组件的一个函数中修改变量并更新组件,想在另一个函数中使用时我们获取到的就只会是初始值了。

可以看到,函数式组件是没有状态的!而react引入hook的原因就是补全函数式组件在这方面的缺陷。比如useState,当函数重新渲染时,state能够从状态池中获取到上次render的状态,像useEffect能根据变量来确定是否需要渲染,从而起到生命周期函数的作用。

也就是说,如果我们希望有一个能在每次渲染的时候不被重新初始化的变量,那么我们就需要借助hook了。

那么问题又来了,我们应该用哪一个hook呢?这里我推荐一个:useRef

useRef

我们使用useRef()创建的变量不会每次都被重新渲染

1
2
let count = 0 // 每次render都会init
let count = useRef(0) // rerender时不会init

useRef的特性如下:

  • ref的值通过current属性获取

  • ref是可以更改的

  • 更改ref的值不会引起rerender

  • 如果ref的值被用于渲染,那么则不可更改

  • 不建议在组件渲染中写ref的current,推荐在useEffectevent handler中使用使用ref.current

可以看到,ref就是为我们保存不用每次初始化而且不必渲染的变量而生的。

useRef与useState

那么为什么我们要用ref而不去使用state呢?这两个hook有两个非常大的区别:

  • ref不会引起rerender,而state会。当我们调用setState时,会触发rerender,而在使用ref就不必担心这个,你可以随意的使用

  • ref是同步的,state是异步的。当我们同步的使用useState更新数据之后,我们会获取不到最新的值,因为他是异步更新的。而ref则不会有这样的问题,你可以在更新之后立刻获取到最新的值。

所以对我现在的需求来说,useRef要比useState合适的多。

使用useRef操作dom

useRef的另一个重要的作用就是操作dom,我们在这边也顺带提一下吧。

我们可以这样使用ref:

1
2
3
4
5
6
7
8
9
10
11
12
const domRef = useRef(null)

function focusInput(){
domRef.current.focus();
}

return (
<>
<input ref={domRef}/>
<button onClick={focusInput}>click to focus<button>
</>
)

我们通过jsx中的VNODE的ref属性属性传递我们的ref,这样react会在渲染的时候自动将current的值设置为node。然后我们就可以访问到这个node了。

当这个node被从页面中移除时,ref.current也会被设置为null

总结

如果你希望在react函数式组件中保存一个不会每次渲染时更新并且无须被渲染的值,那么useRef是你的不二之选


为何不推荐在react组件中直接定义变量?探秘useRef的使用以及userRef与useState的区别
2023/09/25/technology/react/why_useref/
作者
charlesix59
发布于
2023年9月25日
许可协议