引言💭
在 React 中,ref
是一个重要的功能,用于直接访问 DOM 元素或组件实例。通常,我们使用 ref
来实现一些需要直接操作 DOM 的场景,例如焦点管理、文本选择或动画等。
在 React 中,
ref
主要有三种形式:字符串形式、回调形式和createRef
。
一、字符串形式的 ref
(不推荐使用)
ref
可以使用字符串形式来引用 DOM 元素或组件实例,如下所示:
scala
class MyComponent extends React.Component {
render() {
return <div ref="myDiv">Hello</div>;
}
componentDidMount() {
console.log(this.refs.myDiv); // 通过 refs 获取 DOM 元素
}
}
在组件挂载后,React 会在 refs
对象中自动为每个字符串形式的 ref
创建一个属性,指向对应的 DOM 元素或组件实例。
使用场景
- 字符串形式的
ref
在早期版本中常用于引用 DOM 元素,尤其是对于较简单的组件而言。 - 然而,其缺乏灵活性,且容易导致潜在的性能问题和调试困难。因此,开发者应避免使用字符串形式的
ref
。
二、回调形式的 ref
类方法中的回调 ref
在 React 中,回调形式的 ref
是通过将一个函数传递给 ref
属性来动态设置引用的方式。这个函数会在组件挂载时被调用,并将对应的 DOM 元素或组件实例作为参数传递给它。这个方式通常用于需要在组件生命周期的特定时刻访问 DOM 或组件实例的情况。
scala
class MyComponent extends React.Component {
setRef = (element) => {
this.myDiv = element; // 获取 DOM 元素
};
render() {
return <div ref={this.setRef}>Hello</div>;
}
componentDidMount() {
console.log(this.myDiv); // 通过 this.myDiv 获取 DOM 元素
}
}
在这个例子中,ref={this.setRef}
将 setRef
方法作为回调函数传递。当组件挂载时,React 会调用 setRef
函数,并将 DOM 元素作为参数传入。这样,this.myDiv
就能引用到挂载的 DOM 元素。
内联回调函数
除了使用类方法来定义回调函数,你还可以将回调函数直接写成内联函数,进一步简化代码。这种写法特别适用于一些简单的场景,避免了额外定义方法。
scala
class MyComponent extends React.Component {
render() {
return <div ref={(element) => { this.myDiv = element; }}>Hello</div>;
}
componentDidMount() {
console.log(this.myDiv); // 通过 this.myDiv 获取 DOM 元素
}
}
在这个例子中,ref={(element) => { this.myDiv = element; }}
就是一个内联的回调函数。每当 DOM 元素挂载时,React 会调用该回调,并将 DOM 元素作为参数传入。内联函数写法使得代码更加简洁,适合不需要在其他地方使用 ref
的情况。
使用场景
- 动态引用 DOM 元素 :如果你需要动态访问不同的 DOM 元素(例如多个同类型的元素),回调形式的
ref
非常有用。每当元素挂载或卸载时,回调函数会被自动调用,从而让你能够及时访问或清理引用。 - 条件渲染 :在某些条件下渲染不同的 DOM 元素,并需要访问它们时,回调形式的
ref
可以确保你在元素实际挂载后才获得对它的引用。
三、createRef
(推荐)
createRef
是 React 16.3 引入的一个新 API,是现代 React 中推荐使用的 ref
创建方式。与回调函数形式不同,createRef
提供了一种更加可靠和清晰的方式来引用 DOM 元素或组件实例,并且与每个组件实例绑定,确保 ref
在组件的生命周期内保持一致。
为什么推荐使用 createRef
?
createRef
创建的 ref
是专人专用的 ,每个组件实例都会拥有一个独立的 ref
对象。在组件的生命周期内,ref
的 current
属性会保持对相应 DOM 元素的引用,且不会因为重新渲染而发生变化,这使得它比回调形式的 ref
更加稳定和高效。
在类组件中的使用
scala
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myDivRef = React.createRef(); // 使用 createRef 创建 ref
}
componentDidMount() {
console.log(this.myDivRef.current); // 通过 current 获取 DOM 元素
}
render() {
return <div ref={this.myDivRef}>Hello</div>;
}
}
在这段代码中,我们通过 React.createRef()
创建了一个 ref
,并将其赋值给 this.myDivRef
。每个组件实例都会拥有一个独立的 myDivRef
。当组件挂载时,this.myDivRef.current
会指向 DOM 元素,且在组件的生命周期内不会变化,保证了 ref
的一致性。
在函数组件中的使用
对于函数组件,createRef
并不常用。函数组件通常使用 useRef
来代替 createRef
。useRef
会返回一个带有 current
属性的对象,类似于 createRef
,但它在函数组件中更为常见,并且会在组件的整个生命周期内保持不变。
javascript
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const myDivRef = useRef(null);
useEffect(() => {
console.log(myDivRef.current); // 通过 current 获取 DOM 元素
}, []); // 仅在挂载时调用
return <div ref={myDivRef}>Hello</div>;
}
在这个例子中,useRef
创建了一个 ref
,并将其传递给 div
元素。myDivRef.current
会指向该 DOM 元素。与 createRef
相似,useRef
的 current
属性在组件的整个生命周期内保持不变,适合需要持续引用 DOM 元素的场景。
createRef
和 useRef
的主要区别
- 类组件中使用
createRef
:createRef
在类组件中使用时,每个组件实例都会有一个独立的ref
对象,它是专人专用的,且在组件生命周期内保持一致,不会因重新渲染而变化。 - 函数组件中使用
useRef
:在函数组件中,useRef
是代替createRef
的常用方式,提供了与createRef
类似的功能,且它的引用对象在整个生命周期内保持稳定,避免了回调形式ref
的频繁创建。
使用场景
- 类组件中的引用 :对于类组件,
createRef
是管理ref
的推荐方式,它保证了每个组件实例拥有独立的、稳定的引用。 - 函数组件中的引用 :在函数组件中,
useRef
是创建ref
的标准方式,它提供了与createRef
类似的功能,适合需要持久引用的场景。
结语✒️
持续更新中......🚀🚀🚀
