React
Ref Hooks - useRef & useImperativeHandle
在这篇文章中我们将介绍 React ref 相关知识,包括forwardRef、useRef 和 useImperativeHandle
This entry is part 5 of the seriesenjoy-react-hooks
useRef
在 React 开发中,useRef
是一个非常实用的 Hook,它允许你在不触发组件重新渲染的情况下,访问和修改 DOM 元素或保存任何可变的值。这个功能对于实现一些特定的交互效果,如聚焦输入框、测量元素大小或跟踪组件内部状态而不引起更新,尤其有用。
语法
useRef
返回一个可变的 ref
对象,其 .current
属性被初始化为传入的参数(initialValue
)。返回的 ref
对象在组件的整个生命周期内持续存在,即使在重新渲染时也保持不变。这意味着你可以使用它来存储任何需要跨渲染周期保留的数据,而不仅仅是对 DOM 的引用。
js
const ref = useRef(initialValue)
initialValue
:ref
对象的current
属性的初始值。可以是任意类型的值。这个参数在首次渲染后被忽略。ref
: 一个只有current
属性的对象:current
: 初始值为传递的initialValue
。之后可以将其设置为其他值。如果将ref
对象作为一个 JSX 节点的 ref 属性传递给 React,React 将为它设置current
属性。
ref vs state
ref
和 state
在 React 中都用于管理组件的数据,但它们的主要区别在于如何影响组件的渲染:
改变 ref 不会触发重新渲染
下面案例中分别创建了两个计数器: StateCounter
和 RefCounter
, 分别点击按钮并观察页面及控制台变化。
通过上面案例不难发现:
- 当点击
StateCounter
时,控制台打印 state count数值变化,同时UI更新。 - 当点击
RefCounter
时,控制台打印 ref count 数值变化,但UI不会更新。
以下是 state
和 ref
的对比:
ref | state |
---|---|
useRef(initialValue) 返回 { current: initialValue } | useState(initialValue) 返回 state 变量的当前值和一个 state 设置函数 ( [value, setValue] ) |
更改时不会触发重新渲染 | 更改时触发重新渲染 |
可变 —— 你可以在渲染过程之外修改和更新 current 的值 | 不可变 —— 你必须使用 state 设置函数来修改 state 变量,从而排队重新渲染 |
你不应在渲染期间读取(或写入) current 值 | 你可以随时读取 state。但是,每次渲染都有自己不变的 state 快照。 |
通过ref操作DOM
使用 ref
操作 DOM 是非常常见的行为。React 内置了对它的支持。
- 首先声明一个初始值为
null
的ref
const inputEl = useRef(null) - 然后将 ref 对象作为 ref 属性传递给想要操作的 DOM 节点的 JSX:
<input ref={inputEl} type='text' />
- 当 React 创建 DOM 节点并将其渲染到屏幕时,React 将会把 DOM 节点设置为
ref
对象的current
属性。现在可以借助 ref 对象访问<input>
的 DOM 节点,并且可以调用类似于 focus() 的方法:inputEl.current.focus()
useImperativeHandle
这是一个很少使用的hook, 只有当你需要 forwardRef 时, 才有可能用得到。常用于向父组件”expose“(暴露)方法。
语法
在组件顶层通过调用 useImperativeHandle 来自定义 ref 暴露出来的句柄:
import { forwardRef, useImperativeHandle } from 'react';const CustomInput = forwardRef(function CustomInput(props, ref) {useImperativeHandle(ref, () => {return {// ... 你的方法 ...};}, []);// ...
用途
useImperativeHandle
用于向父组件暴露暴露一个自定义的ref
句柄,该句柄通常会挂载一些自定义方法。
例如: 我们定义了一个组件CustomInput
, 该组件对外暴露了一个focus
方法,以便调用方聚焦CustomInput
。完整代码如下:
Table of Contents