ReactJS - Refs 和 DOM



React 会随着组件状态的变化自动输出 HTML 元素。这极大地简化了 UI 开发,因为只需要更新组件的状态即可。但是,传统上,直接访问 DOM 元素是更新组件 UI 的规范。

有时我们可能需要回退到直接访问 DOM 元素并更新 React 应用中的 UI。React ref 在这种情况下提供了帮助。它提供了对 DOM 元素的直接访问。此外,它确保组件与 React 虚拟 DOM 和 HTML DOM 顺利协作。

React 提供了一个函数 createRef,用于在基于类的组件中创建 ref。让我们在本节中学习如何使用 createRef。

createRef 方法的签名

createRef 的目的是返回一个可变对象,该对象将在重新渲染之间持久化。createRef 的签名如下所示:

<refObj> = React.createRef()

这里,refObj 是 hook 返回的对象

为了将 DOM 对象自动附加到refObj,应将其设置在元素的 ref 属性中,如下所示:

<input ref={refObj} />

要访问附加的 DOM 元素,请使用refObjcurrent 属性,如下所示:

const refElement = refObj.current

应用 ref

让我们在本节中学习如何通过创建一个 React 应用来应用createRef

首先,创建一个新的 React 应用并使用以下命令启动它。

create-react-app myapp
cd myapp
npm start

接下来,在 components 文件夹下创建一个 React 组件 SimpleRef (src/components/SimpleRef.js)

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 属性将其附加到相关元素

  • 创建一个 ref,this.labelRef 来表示问候消息元素,并通过 ref 属性将其附加到相关元素

  • 将事件处理程序 this.handleChange 附加到输入元素。事件处理程序使用this.inputRef ref 获取问候消息,并使用 this.labelRef ref 更新消息

接下来,在浏览器中打开应用程序并输入您的姓名。应用程序将更新问候消息,如下所示。

Applying Ref

检查您的控制台,您会注意到组件没有重新渲染。由于 React 仅在状态更改时重新渲染,而 ref 不会进行任何状态更改,因此组件不会重新渲染。

接下来,点击“+”按钮。它将通过重新渲染组件来更新计数器,因为状态 (count) 发生了变化。如果您仔细观察,您会发现消息保持不变。这种行为的原因是 ref 值在 React 的渲染之间得以保留。

createRef 的用例

createRef 的一些用例如下:

访问 JavaScript DOM API - JavaScript DOM API 提供了丰富的功能来操作应用程序的 UI。当应用程序功能需要访问 JavaScript DOM API 时,可以使用 createRef 来检索原始 DOM 对象。一旦检索到原始 DOM 对象,应用程序就可以使用 DOM API 来访问所有功能。以下是一些 DOM API 的示例:

  • 聚焦输入元素

  • 选择文本

  • 使用媒体播放 API 播放音频或视频

命令式动画 - Web Animation API 通过命令式编程而不是声明式编程提供了一套丰富的动画功能。要使用 Web Animation API,我们需要访问原始 DOM。

与第三方库集成 - 由于第三方库需要访问原始 DOM 来执行其功能,因此必须使用 createRef 从 React 获取 DOM 参考并将其提供给第三方库。

总结

尽管 React 开发 UI 的方式简单易用,但在某些情况下,基于 DOM API 开发 UI 也有其自身的优势。createRef hook 完美地适用于这些场景,并提供了简单易用的 API 来直接访问 DOM 元素及其 API。

广告