目录

类组件中ref的使用
在类组件中,基于ref可以做的事情
1、赋值给一个标签,获取DOM元素
2、赋值给一个类子组件:获取子组件实例「可以基于实例调用子组件中的属性和方法」
3、赋值给一个函数子组件:报错「需要配合React.forwardRef
实现ref
转发,获取子组件中的某一个DOM元素」
ref的使用方法:
1、ref='box'
this.refs.box
获取(不推荐使用,严格模式报错)
2、ref=(x=>this.box= x)
this.box
获取
3、let box = React.creatdRef()
创建一个ref
对象
<h2 ref={
this.box}>
通过this.box.current
获取DOM元素
函数组件中useRef
useRef 可以用来创建一个跨渲染保持不变的引用,通常用来获取 DOM 元素或保存任何跨渲染保持不变的值。
基本语法:
const myRef = useRef(initialValue);
initialValue
是useRef
创建的引用的初始值。myRef
是一个对象,具有.current
属性,可以通过.current
来访问或修改该引用的值。
函数组件中
1、基于ref = {函数}的方式(不推荐使用)
基于ref = {函数}
的方式,可以把创建的DOM元素(或者子组件的实例)赋值给box
变量
let box;
useEffect(()=>{
console.log(box)
},[])
return <div ref={
x=>box=x}></div>
2、基于React.createRef创建ref对象来获取想要的内容
let box = React.createRef();
useEffect(()=>{
console.log(box.current)
},[])
return <div ref={
box}></div>
3、useRef
函数组件中,可以基于 useRef Hook函数,创建ref对象(React.createRef创建ref对象,函数组件、类组件都可以用)
let box = useRef(null);
console.log(box)
useEffect(()=>{
console.log(box.current)
},[])
return <div ref={
box}></div>
4、useRef 和 React.createRef的区别
useRef
在每一次组件更新的时候(函数重新执行),再次执行useRef
方法的时候,不会创建新的REF
对象了,获取到的还是第一次创建的那个REF对象
!!React.createRef
在每一次组件更新的时候,都会创建一个全新的REF
对象出来,比较浪费性能!!
而类组件只有在初始渲染会创建ref
对象,组件更新时是render函数执行,不会再次重新创建ref对象
总结:在类组件中,创建REF对象,我们基于 React.createRef 处理;但是在函数组件中,为了保证性能,我们应该使用 useRef 处理!!
我们来测试下上述的结论是否正确:
let prev1, prev2;
const Demo = function Demo() {
let [num, setNum] = useState(0);
let box1 = useRef(null),
box2 = React.createRef();
if (!prev1) {
// 第一次DEMO执行,把第一次创建的REF对象赋值给变量
prev1 = box1;
prev2 = box2;
} else {
// 第二次DEMO执行,我们验证一下,新创建的REF对象,和之前第一次创建的REF对象,是否一致?
console.log(prev1 === box1); //true useRef再每一次组件更新的时候(函数重新执行),再次执行useRef方法的时候,不会创建新的REF对象了,获取到的还是第一次创建的那个REF对象!!
console.log(prev2 === box2); //false createRef在每一次组件更新的时候,都会创建一个全新的REF对象出来,比较浪费性能!!
// 总结:在类组件中,创建REF对象,我们基于 React.createRef 处理;但是在函数组件中,为了保证性能,我们应该使用专属的 useRef 处理!!
}
useEffect(() => {
console.log(box1.current);
console.log(box2.current);
});
return <div className="demo">
<span className="num" ref={
box1}>{
num}</span>
<span className="num" ref={
box2}>哈哈哈</span>
<Button type="primary" size="small"
onClick={
() => {
setNum(num + 1);
}}>
新增
</Button>
</div>;
};
5、获取子组件对象
父组件
const Demo = function Demo() {
let x = useRef(null);
useEffect(() => {
console.log(x.current);
}, []);
return <div className="demo">
<Child ref={
x} />
</div>;
};
子组件为类组件时
基于ref
获取子组件的实例,这样基于实例,可以调用子组件内部,挂载到实例上的东西
class Child extends React.Component {
state = {
x: 1000 };
render() {
return <div className="child-box">
{
this.state.x}
</div>;
}
}
子组件为函数组件
基于React.forwardRef
实现ref
转发,目的:获取子组件内部的某个元素
const Child = React.forwardRef(function Child(props, ref) {
// console.log(ref); //在DEMO中,调用Child的时候,传递的ref对象「x」
return <div className="child-box">
<span ref={
ref}>哈哈哈</span>
</div>;
});
useImperativeHandle
在函数子组件内部有自己的状态和方法时,如何实现:基于React.forwardRef
实现ref
转发的同时,获取函数子组件内部的状态或者方法呢?k可以使用useImperativeHandle
useImperativeHandle
允许你在使用 forwardRef
转发 ref
时自定义暴露给父组件的实例值。简单来说,它可以让你控制通过ref
传递到父组件的对象和方法。
语法:
其依赖项dependencies
和 useEffect 的依赖项用法一样
useImperativeHandle(ref, () => {
return {
methodName: () => {
// 实现方法
}
};
}, [dependencies]);
-ref
是父组件传递的 ref
,通常与 forwardRef
一起使用。
- 第二个参数是一个返回对象的函数,这个对象包含了你希望暴露给父组件的属性和方法。
-dependencies
可以是一个依赖数组,只有当这些依赖发生变化时,暴露的值才会更新。
父组件
调用子组件中的submit
方法。
const Demo = function Demo() {
let x = useRef(null);
useEffect(() => {
console.log(x.current,"x.current")
console.log(x.current.submit());
}, []);
return <div className="demo">
<Child ref={
x} />
</div>;
};
父组件打印结果如下:
子组件
const Child = React.forwardRef(function Child(props, ref) {
let [text, setText] = useState('你好世界');
const submit = () => {
console.log('我是子组件中的submit方法')
};
useImperativeHandle(ref, () => {
// ref 是父组件传递的 ref,通常与 forwardRef 一起使用。
// 在这里返回的内容,都可以被父组件的REF对象获取到
return {
text,
submit
};
});
return <div className="child-box">
<span>哈哈哈</span>
</div>;
});