首先做个对比:
功能一:引用一个值做持久化记忆
场景:清除定时器
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