Ref从入门到入土

本文介绍了如何在React中使用useRef和useState进行状态管理,以及如何利用forwardRef和useImperativeHandle进行DOM操作和组件自定义方法暴露。重点讨论了useRef的持久化记忆特性在清除定时器中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先做个对比:

 功能一:引用一个值做持久化记忆

场景:清除定时器

import { useRef } from "react"
import { useState } from "react"
// ref:1.引用一个值 做持久化记忆 
// let num = useRef(1)
// console.log(num.current++);
// 避免渲染ref的值,其值改变时不会触发更新(区别于state)
const App = () => {

    const [count, setCount] = useState(0)

    // let timer = null
    // const handleClick = () => {
    //     setCount(count + 1)

    //     // 不能有效清除定时器,因为每次只能清除当前作用域的timer,但是每次setState都会产生新的作用域,则多次点击会导致定时器累加
    //     clearInterval(timer)
    //     timer = setInterval(() => {
    //         console.log('setInterval...');
    //     }, 1000);
    // }

    let timer = useRef(null)
    const handleClick = () => {
        setCount(count + 1)

        // ref具有记忆性,可以拿到第一次产生的timer,然后清除,保证每次只有一个定时器在
        clearInterval(timer.current)
        timer.current = setInterval(() => {
            console.log('setInterval...');
        }, 1000);
    }


    return (<>
        hello hook
        <button onClick={handleClick}>按钮</button>
        <br />
        count:{count},

    </>)
}

export default App

 功能二:在react中操作dom(避免原生写法

const App = () => {

    const myRef = useRef(null)
    const fun = () => {
        console.log(myRef.current.innerHTML);
        myRef.current.style.color = 'skyblue'
    }
    const list = [
        { id: 1, text: 'aaa' },
        { id: 2, text: 'bbb' },
        { id: 3, text: 'ccc' }
    ]
    return (
        <>
            <button onClick={fun}>点击让div变色</button>
            <div ref={myRef}>div</div>

            {/* 循环中操作ref可以使用回调写法 */}
            <ul>
                {
                    list.map((item) => {
                        return <li key={item.id} ref={(mf) => { mf.style.background = 'pink' }}>{item.text}</li>
                    })
                }
            </ul>
        </>
    )
}

export default App 

注意:当给子组件添加ref时,需要对其 forwardRef 转发,用于向父组件公开其dom


const Zi = forwardRef(function myInput(props, refs) {
    return <input type="text" ref={refs} />
})

const App = () => {
    const myref = useRef(null)
    const fn = () => {
        myref.current.focus()
        myref.current.style.background = 'skyblue'
    }
    return (<>
        hello App
        <button onClick={fn}>点击变色</button>
        <Zi ref={myref} />
    </>)



}

export default App

进阶:useImperativeHandle用于为组件自定义暴露方法

import { useRef, forwardRef, useImperativeHandle } from "react"

const Zi = forwardRef(function myInput(props, refs) {
    const inputRef = useRef(null)
    useImperativeHandle(refs, () => {
        return {
            myFocus() {
                inputRef.current.focus()
            },
            focusAndStyle() {
                inputRef.current.focus()
                inputRef.current.style.background = 'red'
            }
        }
    })
    return (
        <input type="text" ref={inputRef} />
    )
})
const App = () => {
    const myref = useRef(null)
    const fn = () => {
        myref.current.myFocus()
        myref.current.focusAndStyle()
        // 以下会报错 myref.current.focus is not a function,因为只有以上俩方法暴露了
        // myref.current.focus()  
    }
    return (<>
        hello App
        <button onClick={fn}>点击</button>
        <Zi ref={myref} />
    </>)

}

export default App

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白目

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值