ReactJS - Refs 和 DOM
React 会在组件状态发生变化时自动发出 HTML 元素。这大大简化了 UI 开发,因为只需更新组件的状态即可。但是,传统上,直接访问 DOM 元素是更新组件 UI 的常态。
有时我们可能需要回退到直接访问 DOM 元素并更新 React 应用程序中的 UI。React ref 在此场景中提供帮助。它提供对 DOM 元素的直接访问。此外,它确保组件能够与 React Virtual DOM 和 HTML DOM 顺利配合使用。
React 提供了一个函数 createRef,用于在基于类的组件中创建 ref。本章我们来学习如何使用 createRef。
createRef 方法的签名
createRef 的目的是返回一个可变对象,该对象将在重新渲染之间持续存在。createRef 的签名如下 −
<refObj> = React.createRef()
这里,refObj 是Hooks(钩子)返回的对象
要自动将 DOM 对象附加到 refObj,应在元素的 ref props 中设置它,如下所示 −
<input ref={refObj} />
要访问附加的 DOM 元素,请使用 refObj 的 current 属性,如下所示 −
const refElement = refObj.current
应用 ref
让我们在本章中通过创建一个 React 应用程序来学习如何应用 createRef。
首先,创建一个新的 React 应用程序并使用以下命令启动它。
create-react-app myapp cd myapp npm start
接下来,在组件文件夹 (src/components/SimpleRef.js) 下创建一个 React 组件 SimpleRef
import React from "react"; class SimpleRef extends React.Component { render() { return ( <div>Hello World</div> ); } } export default SimpleRef;
接下来,打开 App.css (src/App.css) 并删除所有样式。然后,打开 App 组件 (src/App.js) 并使用我们新的 SimpleRef 组件更新内容,如下所示 −
import './App.css' import SimpleRef from './Components/SimpleRef' function App() { return ( <div className="container"> <div style={{ padding: "10px" }}> <div> <SimpleRef /> </div> </div> </div> ); } export default App;
接下来,向 SimpleRef 组件添加计数器功能,如下所示 −
import React from "react"; class SimpleRef extends React.Component { constructor(props) { super(props) this.state = { count: 0 } this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState( prevState => ({ count: prevState.count + 1 }) ) } render() { return ( <div> <div>Counter: {this.state.count} <button onClick={this.handleClick}>+</button></div> </div> ) } } export default SimpleRef;
这里我们有,
使用 this.setState 来处理计数器状态变量 (count)。
在 JSX 中呈现计数器状态变量
添加一个按钮并附加一个点击处理程序事件 (this.handleClick),它将使用 this.setState 方法增加计数器
接下来,添加一个输入字段并根据用户在输入字段中输入的值显示问候消息,如下所示 −
import React from "react"; import { createRef } from "react"; class SimpleRef extends React.Component { constructor(props) { super(props) this.state = { count: 0 } this.handleClick = this.handleClick.bind(this); this.handleChange = this.handleChange.bind(this); this.inputRef = createRef() this.labelRef = createRef() } handleClick() { this.setState(prevState => ({ count: prevState.count + 1 })) } handleChange() { this.labelRef.current.innerText = this.inputRef.current.value == "" ? "World" : this.inputRef.current.value } render() { return ( <div> <div>Counter: {this.state.count} <button onClick={this.handleClick}>+</button></div> <div style={{ paddingTop: "5px"}}> <label>Enter your name: </label><input type="text" name="username" ref={this.inputRef} onChange={this.handleChange}/> <br /> <div>Hello, <span ref={this.labelRef}></span></div> </div> </div> ) } } export default SimpleRef;
这里我们有,
创建一个 ref,this.inputRef 来表示输入元素,并通过 ref props 将其附加到相关元素
创建一个 ref,this.labelRef 来表示问候消息元素,并通过 ref props 将其附加到相关元素
将事件处理程序 this.handleChange 附加到输入元素。事件处理程序使用 this.inputRef ref 获取问候消息,并使用 this.labelRef ref 更新消息
接下来,在浏览器中打开应用程序并输入您的姓名。应用程序将更新问候消息,如下所示。

检查控制台,您会注意到组件未重新渲染。由于 react 仅在状态更改时重新渲染,而 ref 不会进行任何状态更改,因此组件未重新渲染。
接下来,单击 + 按钮。当状态(计数)发生变化时,它将通过重新渲染组件来更新计数器。如果仔细观察,您会发现消息保持不变。这种行为的原因是 ref 值在 react 渲染之间得到保留。
createRef 的用例
createRef 的一些用例如下 −
访问 JavaScript DOM API − JavaScript DOM API 提供了丰富的功能集来操作应用程序的 UI。当应用程序功能需要访问 JavaScript DOM API 时,可以使用 createRef 来检索原始 DOM 对象。检索到原始 DOM 对象后,应用程序可以使用 DOM API 访问所有功能。DOM API 的一些示例如下 −
聚焦输入元素
选择文本
使用媒体播放 API 播放音频或视频
命令式动画 − Web 动画 API 通过命令式编程而非声明式编程提供了丰富的动画功能集。要使用 Web 动画 API,我们需要访问原始 DOM。
与第三方库集成 −由于第三方库需要访问原始 DOM 才能执行其功能,因此必须使用 createRef 从 react 获取 DOM 引用并将其提供给第三方库。
摘要
尽管 react 开发 UI 的方式简单易行,但基于 DOM API 开发 UI 在某些情况下有其自身的优势。createRef hook 非常适合这些场景,并提供简单干净的 API 来直接访问 DOM 元素,随后访问其 API。