学习React 的第四天 通过useRef获取DOM

207 阅读2分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

1. 简介

我个人是很喜欢React Hooks的,但是初学者看来是非常混乱的,我们这里就介绍使用一下常用的Hooks

  1. Hook 只能在函数组件中使用,不能在类组件中使用

1.代码学习

1. useRef

  1. useRef返回一个可变的ref对象,有一个current属性,初始值为传入的参数(initialValue)。
  2. 返回的 ref 对象在组件的整个生命周期内持续存在
  3. 这是一种访问DOM的主要方式,和vue2的ref 是一样的

2. 简单使用

  1. 引入Hook

    import { useRef } from "react";
    
  2. 创建一个需要被ref 指定的标签

    function App() {
        return <>
            <input type="text" />
        </>
    }
    
  3. 创建hook实例并绑定标签

    function App() {
        const inputRef = useRef<HTMLInputElement>(null);
        return <>
            <input ref={inputRef} type="text" defaultValue="20"/>
        </>
    }
    
  4. 通过hook获取到ref对象,再通过该对象的current属性得到dom元素

    function App() {
        const inputRef = useRef<HTMLInputElement>(null);
    
        console.log(inputRef.current)
        console.log(inputRef.current?.value)
        console.log(inputRef.current?.style)
    
        return <>
            <input ref={inputRef} type="text" defaultValue="20"/>
        </>
    }
    
  5. 上面直接console 可能获取不到 建议使用 useEffect

    useEffect(() => {
        console.log(inputRef.current)
        console.log(inputRef.current?.value)
        console.log(inputRef.current?.style)
    }, []);
    

    1675650056737.png

  6. 通过ref来修改DOM属性值

function App() {
    const inputRef = useRef<HTMLInputElement>(null);

    function changeInputVal() {
        if (inputRef.current) {
            inputRef.current.value = "50"
        }
    }

    return <>
        <input ref={inputRef} type="text" defaultValue="20"/>
        <button onClick={changeInputVal}>改变</button>
    </>
}
  1. 使用ref绑定自定义组件 (高阶组件)
    1. 需要使用一个新的Hook useImperativeHandle 和 react forwardRef 方法
    2. useImperativeHandle 是官方为了简化ref操作,让子组件暴露出方法和状态给父组件调用, useImperativeHandle是用在子组件上的,同时还需要搭配forwardRef使用
    3. forwardRef接受一个渲染函数,使用该函数来决定为 ref 转发组件显示的内容,详细解说之后再讲解,简单来说就是转发
    
    interface GameProps {
        title: string
        value: string | number
    }
    
    interface GameAttr {
        value?: string
        open: Function
    }
    
    const GameCom = forwardRef<GameAttr, GameProps>(({ title, value }, ref) => {
        function message() {
            alert("game组件的message 方法")
        }
        useImperativeHandle(ref, () => ({ open: message }));
        return <span>
            <h3>{title}</h3>
            <input type="text" defaultValue={value}/>
        </span>
    })
    
    1. GameProps 是该组件需要的属性
    2. GameAttr 是该组件暴露给父组件的方法和状态
    3. { title, value } 就是结构后的 Props
  2. 父组件中调用
function App() {
    const gameRef = useRef<GameAttr>(null);

    return <>
        <ul>
            <li>
                <GameCom ref={gameRef} title="游戏组件" value="game001"></GameCom>
                <button onClick={() => gameRef.current?.open()}>按钮{gameRef.current?.value}</button>
            </li>
        </ul>
    </>
}
  1. ref={gameRef} 来绑定子组件
  2. title="游戏组件" value="game001" 传入必须的属性
  3. 通过gameRef实例来获取子组件暴露的状态和方法

3. 总结

  1. 学习了通过useRef 获取到DOM元素
  2. 创建高阶自定义组件,并暴露出状态和方法