React Hooks 系列:useRef 的解析笔记
useRef
用法详解
useRef
是 React 中的一个 Hook,用于在函数组件中创建和访问可变的引用对象。它的主要用途包括:
- 访问 DOM 元素:通过
useRef
可以直接访问 DOM 节点。 - 存储可变值:
useRef
可以用来存储任何可变值,且在组件重新渲染时不会丢失。
基本用法
import React, { useRef, useEffect } from 'react';
function MyComponent() {
// 创建一个 ref 对象
const myRef = useRef(null);
useEffect(() => {
// 访问 DOM 元素
if (myRef.current) {
myRef.current.focus();
}
}, []);
return (
<div>
{/* 将 ref 绑定到 DOM 元素 */}
<input ref={myRef} type="text" />
</div>
);
}
详细说明
1. 创建 ref 对象
- 使用
useRef(initialValue)
创建一个 ref 对象。 initialValue
是 ref 对象的初始值,通常为null
。
2. 访问 ref 对象
- 通过
myRef.current
访问 ref 对象的当前值。 - 对于 DOM 元素,
myRef.current
指向该 DOM 节点。
3. 更新 ref 对象
- 通过
myRef.current = newValue
更新 ref 对象。 - 更新 ref 对象不会触发组件重新渲染。
使用场景
1. 访问 DOM 元素
- 常用于表单输入、焦点管理、动画等场景。
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// 点击按钮时聚焦输入框
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
2. 存储可变值
- 用于存储计时器 ID、上一次的 props 或 state 等。
function Timer() {
const timerId = useRef(null);
const startTimer = () => {
timerId.current = setInterval(() => {
console.log('Timer tick');
}, 1000);
};
const stopTimer = () => {
clearInterval(timerId.current);
};
return (
<div>
<button onClick={startTimer}>Start Timer</button>
<button onClick={stopTimer}>Stop Timer</button>
</div>
);
}
注意事项
- 不会触发重新渲染:更新
useRef
的值不会导致组件重新渲染。 - 初始值:
useRef
的初始值只在组件挂载时设置一次,后续渲染时不会重新初始化。 - 避免滥用:虽然
useRef
可以存储任意值,但应谨慎使用,避免破坏 React 的数据流。
useRef
和 createRef
的区别
useRef
和 createRef
都是 React 中用于创建引用(ref)的工具,但它们在用法、行为和应用场景上有一些关键区别。
1. useRef
- 使用场景:用于函数组件。
特点:
- 在函数组件的整个生命周期中,
useRef
返回的 ref 对象是持久化的,即使组件重新渲染,useRef
的值也不会丢失。 - 适合存储可变值(如 DOM 引用、计时器 ID 等),且不会触发组件重新渲染。
- 每次渲染时,
useRef
返回的是同一个 ref 对象。
- 在函数组件的整个生命周期中,
2. createRef
- 使用场景:通常用于类组件。
特点:
- 每次组件渲染时,
createRef
都会创建一个新的 ref 对象。 - 如果用于函数组件,每次渲染都会生成一个新的 ref,导致 ref 的值丢失。
- 适合类组件中需要动态创建 ref 的场景。
- 每次组件渲染时,
3. 主要区别
特性 | useRef | createRef |
---|---|---|
适用组件类型 | 函数组件 | 类组件 |
生命周期 | 持久化,组件重新渲染时不会丢失 | 每次渲染都会创建新的 ref 对象 |
性能 | 更高效,适合频繁更新的场景 | 每次渲染都会创建新的对象,性能稍差 |
使用场景 | 函数组件中访问 DOM 或存储可变值 | 类组件中访问 DOM 或动态创建 ref |
为什么函数组件中推荐使用 useRef
?
- 在函数组件中,每次渲染都会重新执行函数体。如果使用
createRef
,每次渲染都会创建一个新的 ref 对象,导致 ref 的值丢失。 useRef
在函数组件的整个生命周期中会返回同一个 ref 对象,确保 ref 的值在重新渲染时不会丢失。
错误示例(函数组件中使用 createRef
):
function MyComponent() {
const myRef = createRef(); // 每次渲染都会创建新的 ref
useEffect(() => {
console.log(myRef.current); // 可能为 null,因为每次渲染都会重新创建 ref
}, []);
return <div ref={myRef}>Hello, createRef!</div>;
}
正确示例(函数组件中使用 useRef
):
function MyComponent() {
const myRef = useRef(null); // 持久化的 ref
useEffect(() => {
console.log(myRef.current); // 正常访问 DOM 元素
}, []);
return <div ref={myRef}>Hello, useRef!</div>;
}
总结
useRef
:用于函数组件,持久化 ref 对象,适合存储可变值或访问 DOM 元素。createRef
:用于类组件,每次渲染都会创建新的 ref 对象,适合类组件中的动态 ref 需求。
在函数组件中,优先使用 useRef
,而在类组件中,使用 createRef
是更合适的选择。理解它们的区别和适用场景,可以帮助你更好地管理 React 组件中的状态和副作用。