ReactHooks - useRef

211 阅读2分钟

这是我参与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,也就是说是当前的,而不是在三秒中改变后的。

  1. 在延迟操作中获取到最新的值

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的重新渲染。::

  1. 模拟类式组件update生命周期

可以通过useRef配合useEffect模拟每次更新时执行的生命周期函数。

const didMountRef = useRef(false)
useEffect(()=>{
        if (didMountRef.current){
            console.log('this is updated')
        }else {
            didMountRef.current = true
        }
    })
  1. 可以绑定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 节点。