这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战
引例
用create-react-app创建一个项目。
写一个点击按钮增加点赞组件
const LikeButton:React.FC = () => {
const [like, setLike] = useState(0)
function handleAlertClick(){
setTimeout(()=>{
alert('you click on' + like)
},3000)
}
return (
<div>
<button
onClick={() => {setLike(like + 1)}}>
{like}👍
</button>
<button onClick={handleAlertClick}>Alert!</button>
</div>
);
};
export default LikeButton
将这个组件引入到App.tsx中。
当前的效果就是点击点赞按钮,然后like值一直加,有一个Alert!按钮可以输出当前有多少点赞。
但是我们做一个操作,那就是点击输出点赞后,在setTimeout等待的这三秒内继续去点击👍,结果会变化吗?
答案是输出的是你在点击Alert!前当前的like值,而你在这三秒内点击的值并没有获取到。这是为什么呢?
每一次渲染的like都是独立的,存在在闭包中,而Alert!调用的函数中like引用的是闭包中的like,也就是说是当前的,而不是在三秒中改变后的。
-
在延迟操作中获取到最新的值
useRef可以解决这个问题,也就是说Alert之后3秒要获取最新点击的like值,而不是点击时的值。
这样声明
export const LikeButton: React.FC = () => {
const [like,setLike] = useState(0)
const likeRef = useRef(0)
function handleLikeClick(){
setTimeout(()=>{
alert('likeState'+like+','+'likeRef'+likeRef.current)
},1000)
}
return (
<div>
<button onClick={() => {
setLike(like+1);
likeRef.current++
}}>{like}👍</button>
<button onClick={handleLikeClick}>查看当前的like</button>
</div>
);
};
通过likeRef.current得到的就是最新的like了。::Ref在所有Render中都只有唯一的引用。不会独立于每一次渲染。但是和state不同,修改Ref的值不会触发render的重新渲染。::
-
模拟类式组件update生命周期
可以通过useRef配合useEffect模拟每次更新时执行的生命周期函数。
const didMountRef = useRef(false)
useEffect(()=>{
if (didMountRef.current){
console.log('this is updated')
}else {
didMountRef.current = true
}
})
-
可以绑定DOM节点,对DOM进行操作
可以实现一个页面渲染完毕和每次更新时input框就聚焦的功能
export const LikeButton: React.FC = () => {
const domRef = useRef<HTMLInputElement>(null)
useEffect(() => {
if (domRef&&domRef.current){
domRef.current.focus()
}
})
return (
<div>
<input type="text" ref={domRef}/>
</div>
);
};
无论这个DOM节点如何变化,React 都会将 ref 对象的 .current 属性设置为相应的 DOM 节点。