前言
在看到ahooks库中看到UseMemoizedFn的源码时,发现了使用useRef的身影,然后,就想到之前一般都是使用userRef来来声明一个ref对象,该ref对象一般都是用来操作DOM节点对象的,没想到这个hook的实现还使用到了useRef,于是就有了这篇文章,好奇useRef的作用主要作用是什么?
useRef
官方文档地址:zh-hans.react.dev/reference/r…
建议大家一般遇到什么问题,一定要先看官网,官网其实把所有的用法以及注意事项都标注的很清楚,之前就是没看官方文档,只按照自己理解的当ref来使用。从官方文档给出的信息,我们需要读出:
useRef是一个React Hook,它能帮助引用一个不需要渲染的值(直白的理解:就是不需要将值显示在屏幕上的,即屏幕上的值不用随着值变化而更新,可以使用useRef来创建)useRef返回一个可变的ref对象,该对象只有个current属性,初始值为传入的参数- 返回的ref对象在组件的整个生命周期内保持不变
- 当更新current值并不会重新渲染,这是与useState不同的地方
- 更新useRef是side effect(副作用),所以一般写在useEffect或event handler里
- 采用useRef,作为组件实例的变量,
保证获取到的数据肯定是最新的。 - useRef类似于类组件的this。
使用:
- useRef(initialValue):在
组件顶层调用useRef声明一个ref
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
//...
- initialValue: ref对象的
current属性的初始值。可以是任意类型的值.这个参数在首次渲染后被忽略 - useRef返回一个
只有一个属性的对象:即只有属性current,其初始值为传递的initialValue。之后可以将其设置为其他值。如果将ref对象作为一个JSX节点的ref属性传递给React,React将为它设置current属性。在后续的渲染中,useRef将返回同一个对象. - 注意:
- 可以修改ref.current属性。与state不同,他是可变的。然而,如果它持有一个用于渲染的对象(例如state的一部分)。那么就不应该修改这个对象。
- 改变ref.current属性时,React不会重新渲染组件。(
因为React不知道它何时会发生改变,因为ref是一个普通的JS对象) - 除了
初始化外不要再渲染期间写入或者读取ref.current,否则会使组件行为变得不可预测。 - 在严格模式下,React 将会 调用两次组件方法。但这只是开发模式下的行为,不会影响生产模式。每个 ref 对象都将会创建两次,但是其中一个版本将被丢弃。如果使用的是组件纯函数(也应当如此),那么这不会影响其行为。
createRef
- createRef主要用于class组件,而函数组件通常使用useRef;
- createRef创建一个ref对象,该对象可以包含任意值;
使用
import {createRef,Component} from 'react;'
class MyComponent extends Component {
intervalRef = createRef()
}
- createRef不接受任何参数
- 注意事项:
- createRef总是返回一个
不同的对象,这相当于你自己编写了{current:null} - 在函数组件中,一般使用useRef,因为它始终返回相同的对象
- createRef总是返回一个
useRef与createRef的区别
一个组件的正常的生命周期为:创建到挂载组件,更新组件,销毁组件; 在创建到挂载阶段,useRef与createRef没有差别; 更新组件阶段,createRef每次都会返回一个新的引用,而useRef不会随着组件的更新而重新创建 销毁阶段:两者都会销毁
总结
最重要的就是:useRef用于帮助引用一个不需要渲染的值;即在声明之后,后续的渲染中,useRef返回的都是同一个对象,也就是说,改变ref不会触发重新渲染;
useRef 返回一个具有单个 current 属性 的 ref 对象,并初始化为你提供的 初始值。
在后续的渲染中,useRef 将返回相同的对象。你可以改变它的 current 属性来存储信息,并在之后读取它。这会让人联想到 state,但是有一个重要的区别。
改变 ref 不会触发重新渲染。这意味着 ref 是存储一些不影响组件视图输出信息的完美选择。例如,如果需要存储一个 interval ID 并在以后检索它,那么可以将它存储在 ref 中。只需要手动改变它的 current 属性 即可修改 ref 的值:
function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}
//在之后,从ref中读物intervalID便可以清除定时器
function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}