一、什么是useRef
const refContainer = useRef(initialValue);
- useRef 返回一个可变的 ref 对象,其内部只有一个 current 属性被初始化为传入的参数(initialValue)
- useRef 返回的 ref 对象在组件的整个生命周期内持续存在
- 更新 current 值时并不会触发页面的重新渲染(re-render)
- useRef 会在每次渲染时返回同一个 ref 对象
本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。
二、useRef的使用
1. 使用useRef获取DOM元素
import { useRef, MutableRefObject } from 'react';
const Demo = () => {
let inputEle: MutableRefObject<any> = useRef(null);
useEffect(() => {
console.log(inputEle);
}, [])
return (
<>
<input ref={ inputEle } type="text" />
<button onClick={
() => {
inputEle.current.focus();
}
}>输入框聚焦</button>
</>
)
};
export default Demo;
inputEle值如下:
小结: 通过useRef定义inputEle变量,在input 元素上定义ref={inputEle},这样通过inputEle中current保存的值为input DOM 元素,这样就可以操作DOM元素了。
2. 使用useRef获取子组件中的DOM元素
import { useRef } from "react";
const Demo = () => {
let childRef = useRef(null);
return (
<>
<Child ref={ childRef } />
</>
);
};
const Child = () => {
return (
<>
<input type="text" />
</>
);
}
export default Demo;
当我们给子组件加了ref后,控制台会报以下错误:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
上述报错的意思是我们不能直接使用ref给子组件,需要forwardRef进行传递转发。
forwardRef: 将父类的ref作为参数传入函数式组件中
React.forwardRef((props, ref) => {})
用法如下:
import { forwardRef, useEffect, useRef } from "react";
const Demo = () => {
let childRef = useRef(null);
useEffect(() => {
console.log(childRef);
}, [])
return (
<>
<Child ref={ childRef } />
</>
);
};
const Child = forwardRef((props, ref) => {
return (
<>
<input type="text" ref={ ref } />
</>
);
})
export default Demo;
childRef值如下:
3. 使用useRef获取子组件中的属性和方法
useImperativeHandle(ref, createHandle, [deps]);
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值,大多数情况下useImperativeHandle 应当与 forwardRef 一起使用:
import {
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from "react";
const Demo = () => {
let childRef = useRef(null);
useEffect(() => {
console.log(childRef);
}, []);
return (
<>
<Child ref={childRef} />
</>
);
};
const Child = forwardRef((props, ref: any) => {
const [num, setNum] = useState(0);
const handleClick = () => {
console.log("Hello World!");
};
useImperativeHandle(ref, () => {
return {
num,
handleClick,
};
});
return (
<>
</>
);
});
export default Demo;
childRef的值如下: