useRef()
组件中,我们基于ref可以做的事情:
- 赋值给一个标签:获取DOM元素
- 赋值给一个类子组件:获取子组件实例「可以基于实例调用子组件中的属性和方法等」
- 赋值给一个函数子组件:报错「需要配合React.forwardRef实现ref转发,获取子组件中的某一个DOM元素」
类组件中ref的使用方法:
- ref=‘box’
this.refs.box 获取
{不推荐使用}-严格模式下报警告错误- ref={x=>this.box=x}
this.box 获取- this.box=React.createRef() 创建一个ref对象
ref={this.box}
this.box.current 获取DOM元素
函数组件下获取DOM元素:
函数组件中没有this实例,无法像类组件中ref使用方法1一样使用this.refs.xxx获取挂载到实例上的DOM元素。
@1:基于“ref={函数}”的方式,可以把创建的DOM元素(或者子组件的实例)赋值给box变量「不推荐」
const Demo = function Demo() {
let [num, setNum] = useState(0);
let box;
useEffect(() => {
console.log(box);
}, []);
return <div className="demo">
<span className="num" ref={
x => box = x}>{
num}</span>
<Button type="primary" size="small"
onClick={
() => {
setNum(num + 1);
}}>新增</Button>
</div>;
};
@2:也可与基于 React.createRef 创建ref对象来获取想要的内容
const Demo = function Demo() {
let [num, setNum] = useState(0);
let box = React.createRef();
useEffect(() => {
console.log(box.current);
}, []);
return <div className="demo">
<span className="num" ref={
box}>{
num}</span>
<Button type="primary" size="small"
onClick={
() => {
setNum(num + 1);
}}>新增</Button>
</div>;
};
@3:函数组件中,还可以基于 useRef() Hook函数,创建一个ref对象
- React.createRef 也是创建ref对象,既可在类组件中使用,也可以在函数组件中使用。
- useRef 只能在函数组件中使用「所有的React Hook函数,都只能在函数组件中使用,在类组件中使用会报错」。
const Demo = function Demo() {
let [num, setNum] = useState(0);
let box = useRef(null);
useEffect(() => {
console.log(box.current);
}, []);
return <div className="demo">
<span className="num" ref={
box}>{
num}</span>
<Button type="primary" size="small"
onClick={
() => {
setNum(num + 1);
}}>新增</Button>
</div>;
};
方法2和方法3都是通过创建ref对象,在相应标签中设置ref属性等于ref对象使得相应的DOM元素挂载到ref对象的current属性上,第一次渲染后通过获取ref对象的current属性来获取DOM元素,那二者有什么区别呢?
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
console.log(prev2 === box2); //false
}
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>;
};
- useRef在每一次组件更新的时候(函数重新执行),再次执行useRef方法的时候,不会创建新的REF对象了,获取到的还是第一次创建的那个REF对象。
- createRef在每一次组件更新的时候,都会创建一个全新的REF对象出来,比较浪费性能。
- 【但在类组件中使用React.createRef创建ref对象,后续this.setState()等操作使得组件更新时,只会使得render函数重新渲染,不存在新创建ref对象的问题,所以类组件中使用React.createRef()没有上述问题】
- 总结:在类组件中,创建REF对象,我们基于 React.createRef 处理;但是在函数组件中,为了保证性能,我们应该使用专属的 useRef 处理。