本文将重点介绍useRef这个Hook,它可以让你在组件的整个生命周期中访问一个可变的引用对象。
useRef
的主要用途是直接访问DOM
子元素,但这并不是它的唯一用途。useRef
也可以用来保存一个在不同渲染中不变的可变值,例如在使用一些非React
的外部库时很有用。本文将介绍useRef
的基本使用,实现原理,最佳实践和一些常见的问题。
公众号:Code程序人生,个人网站:https://creatorblog.cn
要在组件中创建一个新的引用,可以使用以下代码:
// 创建一个引用
const yourRef = useRef();
你也可以选择用一个默认值来初始化它,只需将它作为参数传递给useRef
即可:
// 创建一个引用
const yourRef = useRef('hello world');
useRef
是一个Hook
,因此只能在函数组件中使用!
要获取和设置引用的值,你可以访问对象的.current
属性,如下所示:
// 创建一个引用
const exampleRef = useRef();
// 设置引用的值
exampleRef.current = "Hello World";
// 访问引用的值:
// 这会在控制台打印"Hello World"
console.log(exampleRef.current);
要访问一个DOM
元素,你可以创建一个引用,然后使用它的ref
属性将它分配给你想要目标的DOM
元素,然后你就可以使用它了。
例如,假设你想要获取一个DOM
元素的像素高度。要做到这一点,你必须访问DOM
元素的offsetHeight
属性。但是如何获取DOM
元素呢?当然是用一个引用。
import { useEffect, useRef } from "react";
export default function App() {
// 创建一个引用
const divElement = useRef();
// 在组件第一次渲染时触发
useEffect(() => {
// 获取div元素的高度
console.log("The height of the div is: ", divElement.current.offsetHeight);
}, []);
return (
<div ref={divElement}>
<h1>Learn about useRef!</h1>
</div>
);
}
在上面的例子中,我使用了useEffect
来确保只有在组件第一次渲染后才调用divElement.current.offsetHeight
。事实上,一开始,引用是undefined
的,只有当组件渲染并且div
被创建后,它才会持有它的DOM
元素值。你可以看到,使用引用可能有些棘手,你必须记住一些事情。
要理解useRef
的工作原理,我们需要先了解一些React
的基础知识。
React
是一个用于构建用户界面的库,它通过一个虚拟的DOM
来管理真实的DOM
。虚拟DOM
是一个JavaScript
对象,它表示真实的DOM
结构,但是更轻量级和高效。React
使用虚拟DOM
来跟踪组件的状态和属性,然后根据需要更新真实的DOM
。
当你在组件中使用useState
或useReducer
等Hook
来管理状态时,你实际上是在更新虚拟DOM
中的状态。每当状态发生变化时,React
都会重新渲染组件,并将新的虚拟DOM
与旧的虚拟DOM
进行比较,找出差异,然后将这些差异应用到真实的DOM
上。这个过程被称为协调(reconciliation)
。
但是,有时候你可能不想让React
管理你的状态,而是想直接操作真实的DOM
。这可能是因为你需要使用一些非React
的库,或者你需要访问一些React
无法提供的DOM
属性或方法。这时候,你就可以使用引用(ref)
来实现。
useRef
的基本实现原理其实很简单,它就是利用了JavaScript
的闭包和对象引用的特性,来创建一个只有一个current
属性的对象,然后将这个对象保存在一个变量中,这个变量在每次渲染时都会被复用,而不会被重新赋值。我们可以用下面的伪代码来模拟useRef
的实现:
// 定义一个变量,用来存储ref对象
let ref;
// 定义useRef函数,接收一个初始值作为参数
function useRef(initialValue) {
// 如果ref不存在,就创建一个新的对象,将初始值赋给它的current属性
if (!ref) {
ref = { current: initialValue };
}
// 返回ref对象
return ref;
}
可以看到,useRef
函数只会在第一次调用时创建一个新的对象,然后将它赋值给ref
变量,之后的调用都会返回这个变量,而不会创建新的对象。这样,我们就可以在组件的不同渲染之间保持一个可变的值,而不用担心它会被重新创建或销毁。
引用是一个对象,它有一个.current
属性,可以指向任何你想要的值。当你创建一个引用时,React
会将它保存在一个内部的数据结构中,这个数据结构不会随着组件的重新渲染而改变。这意味着,你可以在组件的整个生命周期中访问同一个引用对象,而不用担心它会丢失或改变。
当你将一个引用分配给一个DOM
元素时,React
会在渲染时将该元素的实例赋值给引用的.current
属性。这样,你就可以通过引用来直接访问该元素,而不需要通过虚拟DOM
或其他方式。你也可以在任何时候修改引用的值,而不会触发组件的重新渲染,因为引用不是一个状态,而是一个可变的容器。
useRef
是一个非常有用的Hook
,但是也有一些注意事项和最佳实践,我们应该遵守,以避免一些潜在的问题和错误。下面列举了一些常见的最佳实践:
// 使用useRef存储一个定时器
const timer = useRef();
// 在组件卸载时,清除定时器
useEffect(() => {
return () => {
clearInterval(timer.current);
};
}, []);
useRef
是一个非常强大和有用的Hook
,它可以让我们直接访问和操作DOM
元素,以及在组件的不同渲染之间保持一个可变的值。
它的实现原理很简单,就是利用了JavaScript
的闭包和对象引用的特性,来创建一个只有一个current
属性的对象,然后将这个对象保存在一个变量中,这个变量在每次渲染时都会被复用,而不会被重新赋值。
我们在使用useRef
时,应该遵守一些注意事项和最佳实践,以避免一些潜在的问题和错误。useRef
与其他Hook
,比如useState
、useEffect
、useCallback
等,有着不同的功能和优势,我们应该根据不同的场景,选择合适的Hook
来实现我们的需求,从而提高我们的代码的可读性、可维护性和性能。