ReactJS - Refs 和 DOM
你好,未来的 React 开发者们!今天,我们将深入一个激动人心的话题,它将帮助你在 React 应用程序中直接与 DOM 元素交互。系好安全带,因为我们即将探索 Refs 和 DOM 的世界!
Refs 是什么?
在我们深入研究细节之前,先来了解一下 Refs 是什么。在 React 中,“Ref”是“reference”的缩写。它就像给一个特定的元素贴上一个名字标签,这样你以后可以轻松地找到它。想象你在一个大派对上,你想跟踪你的最好的朋友。你可能会给他们戴上一顶特别的帽子或者一个独特名字标签。这就是 React 中 Ref 的作用 - 它帮助你跟踪特定的元素。
我们为什么需要 Refs?
你可能会有疑问,“为什么我们不能只使用普通的 JavaScript 来选择元素?” 在 React 中,我们尽量避免直接操作 DOM(文档对象模型),因为 React 有自己高效更新 UI 的方式。然而,有时我们需要跳出 React 的声明式编程范式,直接与 DOM 元素工作。这时,Refs 就派上用场了!
使用 createRef() 创建 Refs
让我们从如何在 React 中创建一个 Ref 开始。我们使用一个名为 createRef()
的方法。
createRef 方法的签名
createRef()
的签名非常简单:
React.createRef()
就是这样!没有参数,没有复杂度。它返回一个只有一个属性的普通对象:current
。最初,这个 current
属性被设置为 null
。
让我们看一个例子:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
在这个例子中,我们在构造函数中创建了一个 Ref 并将其赋值给 this.myRef
。然后在 render
方法中,我们使用 ref
属性将这个 Ref 附加到一个 div
元素上。
应用 Refs
现在我们已经创建了我们的 Ref,来看看我们如何使用它。应用 Ref 的方法有几种:
1. 在 DOM 元素上使用 Refs
最常见的用例是将 Ref 应用到一个 DOM 元素上:
class AutoFocusInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.focus();
}
render() {
return <input ref={this.inputRef} />;
}
}
在这个例子中,我们为一个输入元素创建了一个 Ref。在组件挂载后,我们使用 Ref 来自动聚焦到输入框。Ref 的 current
属性给了我们访问实际 DOM 节点的权限。
2. 在类组件上使用 Refs
你还可以在类组件上使用 Refs:
class AutoScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
componentDidUpdate() {
const node = this.listRef.current;
node.scrollToItem(0);
}
render() {
return <MyListComponent ref={this.listRef} />;
}
}
在这种情况下,this.listRef.current
将指向 MyListComponent
类的实例。
3. 在函数组件上使用 Refs
函数组件不能直接被赋予 Refs,但你可以使用 forwardRef
函数来传递 Refs:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}
render() {
return <FancyButton ref={this.buttonRef}>点击我!</FancyButton>;
}
}
在这个例子中,FancyButton
使用 forwardRef
来将 Ref 传递给实际的按钮元素。
createRef 的使用场景
现在我们知道如何创建和应用 Refs,让我们看看一些常见的使用场景:
1. 管理焦点、文本选择或媒体播放
class TextInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
focusTextInput = () => {
this.inputRef.current.focus();
}
render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<button onClick={this.focusTextInput}>聚焦输入框</button>
</div>
);
}
}
这个组件允许我们在点击按钮时程序化地聚焦输入框。
2. 触发强制动画
class Animator extends React.Component {
constructor(props) {
super(props);
this.elementRef = React.createRef();
}
animate = () => {
this.elementRef.current.classList.add('animated');
}
render() {
return (
<div>
<div ref={this.elementRef}>动画我!</div>
<button onClick={this.animate}>开始动画</button>
</div>
);
}
}
在这里,我们使用 Ref 来给一个元素添加 CSS 类,触发动画。
3. 与第三方 DOM 库集成
class MapComponent extends React.Component {
constructor(props) {
super(props);
this.mapRef = React.createRef();
}
componentDidMount() {
const mapLibrary = new FancyMapLibrary();
mapLibrary.createMap(this.mapRef.current);
}
render() {
return <div ref={this.mapRef} style={{width: '100%', height: '400px'}} />;
}
}
在这个例子中,我们使用 Ref 来给第三方地图库提供一个 DOM 节点,它可以在其中渲染地图。
结论
Refs 是 React 中一个强大的工具,它允许我们在必要时跳出声明式编程范式。它们提供了一种直接访问 DOM 节点或 React 元素的方式。然而,使用 Refs 需要谨慎。在大多数情况下,你可以通过 React 的声明式 API 实现你的需求。但当你确实需要额外的控制时,Refs 就会派上用场!
记住,能力越大,责任越大。明智地使用 Refs,你的 React 应用程序会感激你的!
以下是我们在本文中讨论过的方法的快速参考表:
方法 | 描述 | 示例 |
---|---|---|
React.createRef() |
创建一个 ref 对象 | this.myRef = React.createRef(); |
ref 属性 |
将 ref 附加到 React 元素 | <div ref={this.myRef} /> |
forwardRef |
允许函数组件接收 refs | const FancyButton = React.forwardRef((props, ref) => ...) |
快乐编码,愿你的 Refs 始终处于当前状态!
Credits: Image by storyset