携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
useRef介绍
useRef主要有以下作用
- 获取dom元素
- 解决hooks陷阱
- 获取变量上一次的值
一:useRef
0. 唯一性
useRef具有唯一性,组件重新加载时,useRef对象始终指向同一块内存,因此useRef是无法使用useEffect进行监听改变的,是毫无意义的。
const divRef = useRef();
useEffect(()=>{
//无法监听到divRef改变,没有意义的操作
},[divRef])
<div ref={divRef}></div>
1.获取dom
import React, { useEffect, useRef } from 'react';
export default function App() {
const pRef = useRef()
//dom已经渲染完成,操作dom
useEffect(()=>{
pRef.current.innerHTML = "dzp"
},[])
return (
<div>
<p ref={pRef}></p>
</div>
);
}
在dom加载完成后,我们获取p元素并添加文本内容
2. 解决hooks陷阱
hooks陷阱指的是变量更新导致函数组件重新加载,如果组件内部存在闭包,则闭包访问的变量始终是初始引用的变量(闭包特点,变量延迟释放)
经典案例
export default memo(function Son(props) {
const [value,setValue] = useState(1)
function getValue() {
setTimeout(() => {
alert(value)
}, 2000);
}
return <div>
{value}
<div onClick={()=>setValue(value+1)}>修改value</div>
<div onClick={getValue}>获取value</div>
</div>
})
我们发现,开始value的值是1。点击获取value。然后快速点击修改value。最后获取的值并不是最新的value。这个就是hooks闭包陷阱问题。
解决方案:使用useRef
上面是官网对useRef的定义,也就是说useRef相当于全局变量,它永远保持唯一性,尽管函数组件数据更新导致页面重新加载,但是useRef保持的仍然是一份相同的数据。因此我们可以用useRef解决上述问题
export default memo(function Son(props) {
const [value,setValue] = useState(1)
const valueRef = useRef(value)
function getValue() {
setTimeout(() => {
alert(valueRef.current)
}, 2000);
}
return <div>
{value}
<div onClick={()=>{setValue(value+1);valueRef.current++}}>修改value</div>
<div onClick={getValue}>获取value</div>
</div>
})
我们通过在修改value的同时,让useRef保持的变量也更新,最后输出的始终是useRef最新的数据。
3.获取上次变量的值
需求:有一个变量num,当num改变时,输出num之前的值和当前最新的数据
import {useEffect, useRef, useState } from "react"
export default memo(function Son(props) {
const [value,setValue] = useState(1)
const valueRef = useRef(value)
useEffect(()=>{
valueRef.current = value
},[value])
return <div>
<div onClick={()=>{setValue(value+1)}}>修改value</div>
<div>以前:{valueRef.current}</div>
<div>当前:{value}</div>
</div>
})
首次valueRef和value都是1.当点击修改value的值成为2时,触发useEffect的num更新回调函数,重点:触发回调函数执行时,num数据和dom已经更新,也就是说界面value已经显示2并且valueRef已经显示1。然后我们才设置了valueRef的值是2,valueRef的值更新并不会触发组件重新加载。
此处不会的原因是没搞清楚 useEffect更新的回调函数执行是在组件监听数据已经更新并且dom已经渲染在页面后执行。
二:ref
给ref传递回调函数可以监听dom的挂载。之前一次在给弹窗组件初始化表单数据时,使用useRef无法监听到表单组件的挂载,导致数据一直无法赋值给表单组件。使用ref可以完美的监听到组件挂载
<input ref={e=>{
//e就是组件input
if(e) {
e.value = '初始的数据'
}
}}/>
总结
- useRef可以操作页面dom
- useRef在组件声明周期内永远是唯一的
- useRef的唯一性可以解决hooks陷阱,可以获取获取变量上次值