ReactJS - 使用 useRef



当组件的状态发生变化时,React 会自动发出 HTML 元素。这极大地简化了 UI 开发,因为它足以更新组件的状态。传统上,直接访问 DOM 元素来更新组件的 UI 是很正常的。

有时我们可能需要回退到直接访问 DOM 元素并更新组件的 UI。React ref 在这种情况下提供帮助。它提供对 DOM 元素的直接访问。此外,它还确保组件与 react Virtual DOM 和 HTML DOM 一起顺利运行。

React 提供了一个函数 createRef 来在基于类的组件中创建 ref。函数组件中 createRef 的对应物是 useRef 钩子。在本章中,让我们学习如何使用 useRef。

useRef 钩子的签名

useRef 的目的是返回一个可变对象,该对象将在重新渲染之间持续存在。useRef的签名如下:


 <refObj> = useRef(<val>)

这里

  • val 是为返回的可变对象 refObj 设置的初始值。
  • refObj 是钩子返回的对象。

要自动将 DOM 对象附加到 refObj,应在元素的 ref props 中设置它,如下所示 -


 <input ref={refObj} />

要访问附加的 DOM 元素,请使用 refObj 的 current 属性,如下所示 -


 const refElement = refObj.current

应用 ref 钩子

在本章中,让我们通过创建一个 react 应用程序来学习如何应用 useRef。

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

create-react-app myapp
cd myapp
npm start

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


function RefInput() {
	 	return <div>Hello World</div>
}
export default RefInput

接下来,更新根组件 (App.js) 以使用我们的新组件。


import RefInput from "./components/RefInput";
function App() {
	 	return (
	 	 	 <div style={{ padding: "5px"}}>
	 	 	 	 	<RefInput />
	 	 	 </div>
	 	);
}
export default App;

接下来,向 RefInput 组件添加计数器功能,如下所示 -


import {useState} from 'react'
function RefInput() {
	 	const [count, setCount] = useState(0)
	 	const handleClick = () => setCount(count + 1)
	 	return (
	 	 	 <div>
	 	 	 	 	<div>Counter: {count} <button onClick={handleClick}>+</button></div>
	 	 	 </div>
	 	)
}
export default RefInput

在这里,我们有,

  • 使用 useState 钩子处理计数器状态变量 (count)。
  • 在 JSX 中呈现了计数器状态变量。
  • 添加了一个按钮并附加了一个点击处理程序事件 (handleClick),该事件将使用 setCount 方法递增计数器。

接下来,添加一个输入字段,并根据用户在输入字段中输入的值显示问候语,如下所示 -


import {useState, useRef} from 'react'
function RefInput() {
	 	const [count, setCount] = useState(0)
	 	const inputRef = useRef(null)
	 	const labelRef = useRef(null)
	 	console.log("RefInput is (re)rendered")
	 	const handleClick = () => setCount(count + 1)
	 	const handleChange = () => labelRef.current.innerText = inputRef.current.
	 	value == "" ? "World" : inputRef.current.value
	 	return (
	 	 	 <div>
	 	 	 	 	<div>Counter: {count} <button onClick={handleClick}>+</button></div>
	 	 	 	 	 	 <div style={{ paddingTop: "5px"}}>
	 	 	 	 	 	 	 	<label>Enter your name: </label><input type="text" name="username"
	 	 	 	 	 	 	 	 	 ref={inputRef} onChange={handleChange}/>
	 	 	 	 	 	 	 	<br />
	 	 	 	 	 	 <div>Hello, <span ref={labelRef}></span></div>
	 	 	 	 	</div>
	 	 	 </div>
	 	)
}
export default RefInput

在这里,我们有 -

  • 创建了一个 ref inputRef 来表示输入元素,并通过 ref props 将其附加到相关元素。
  • 创建了另一个 ref labelRef 来表示问候消息元素,并通过 ref props 将其附加到相关元素。
  • 将事件处理程序 handleChange 附加到输入元素。事件处理程序使用 inputRef ref 获取问候消息,并使用 labelRef ref 更新消息。

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

Applying Ref Hook

检查您的控制台,您会注意到该组件未重新呈现。由于 react 仅在状态更改时重新渲染,而 ref 不执行任何状态更改,因此组件不会被重新渲染。

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

useRef 的用例

useRef 的一些用例如下 -

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

  • 聚焦输入元素
  • 选择文本
  • 使用媒体播放 API 播放音频或视频

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

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

总结

尽管 react 开发 UI 的方式简单易行,但在某些情况下基于 DOM API 开发 UI 有其自身的优势。useRef 钩子非常适合这些场景,并提供简单干净的 API 来直接访问 DOM 元素并随后访问其 API。