CreateRef和useRef
文章目录
- 1. 本质与使用场景
- 2. 生命周期行为
- 3. 功能范围
在 React 中,createRef 和 useRef 都是用于创建引用(ref)来访问 DOM 元素或组件实例的工具,但它们在 使用场景、生命周期行为 和 功能范围 上有显著区别。
1. 本质与使用场景
createRef
是一个 类组件和函数组件通用的 API,用于创建一个 ref 对象。
在 类组件 中,通常在 constructor 中初始化,通过 this.refName 访问。
在 函数组件 中可以直接使用,但每次渲染都会创建一个新的 ref 对象(可能导致不必要的更新)。
// 类组件中使用 createRef
class MyComponent extends React.Component {myRef = React.createRef();componentDidMount() {console.log(this.myRef.current); // 访问DOM元素}render() {return <div ref={this.myRef} />;}
}
useRef
是一个 仅用于函数组件的 Hook
,不仅能创建 ref 对象,还能 保存任意可变值(类似类组件的 this)。
每次渲染返回 同一个 ref 对象(不会重新创建),避免了 createRef 在函数组件中重复创建的问题。
主要用于函数组件中访问 DOM 或存储跨渲染周期的可变数据。
// 函数组件中使用 useRef
function MyComponent() {const myRef = React.useRef(null);React.useEffect(() => {console.log(myRef.current); // 访问DOM元素}, []);return <div ref={myRef} />;
}
2. 生命周期行为
createRef
在函数组件中,每次组件重新渲染时,createRef 都会创建一个 新的 ref 对象。
这可能导致问题:例如在依赖 ref 的 useEffect 中,会因 ref 引用变化而触发不必要的副作用。
function BadExample() {// 每次渲染都会创建新的 ref 对象const myRef = React.createRef(); // 因 myRef 变化,每次渲染都会执行 useEffectReact.useEffect(() => {console.log(myRef.current); }, [myRef]); return <div ref={myRef} />;
}
useRef
在组件的整个生命周期中,useRef 返回的 ref 对象是 同一个(持久化的),不会随渲染重新创建。
这确保了 ref 引用的稳定性,避免了不必要的副作用触发。
function GoodExample() {// 整个生命周期中只创建一次 ref 对象const myRef = React.useRef(null); // 仅在组件挂载时执行一次(因 myRef 不变)React.useEffect(() => {console.log(myRef.current); }, [myRef]); return <div ref={myRef} />;
}
3. 功能范围
createRef
仅用于 创建 ref 对象,功能单一,其 current 属性主要用于关联 DOM 元素或组件。
useRef
除了创建 ref 访问 DOM 外,还可以 存储任意跨渲染周期的可变值(类似类组件的实例变量)。
因为 useRef 的 current 属性变化不会触发组件重新渲染,适合存储不需要引起 UI 更新的数据(如定时器 ID、上一次的状态值等)。
function TimerExample() {const timerRef = React.useRef(null); // 存储定时器IDconst startTimer = () => {timerRef.current = setInterval(() => {console.log('计时中...');}, 1000);};const stopTimer = () => {clearInterval(timerRef.current); // 跨渲染访问定时器ID};return (<div><button onClick={startTimer}>开始</button><button onClick={stopTimer}>停止</button></div>);
}
特性 | createRef | useRef |
---|---|---|
使用场景 | 类组件为主,函数组件慎用 | 仅用于函数组件 |
渲染时的创建行为 | 每次渲染创建新对象(函数组件中) | 始终返回同一个对象(持久化) |
功能范围 | 仅创建 ref 访问 DOM | 创建 ref + 存储跨渲染的可变值 |
与 Hook 配合 | 可能导致不必要的副作用触发 | 适合与 useEffect 等 Hook 配合使用 |
最佳实践
类组件:使用 createRef。
函数组件:优先使用 useRef(既稳定又能扩展存储功能)。
避免在函数组件中使用 createRef,除非明确需要每次渲染创建新的 ref 对象(极少场景)。
//函数组件中使用createRef示例
import React from 'react';function CreateRefInFunction() {// 1. 使用createRef创建ref(每次渲染都会生成新对象)const inputRef = React.createRef();const logRef = React.createRef();// 2. 操作ref的函数(需在DOM挂载后调用)const handleFocus = () => {// 访问DOM元素:current属性指向关联的DOMinputRef.current?.focus();};const handleLog = () => {logRef.current.textContent = `输入值:${inputRef.current?.value || '空'}`;};// 3. 注意:每次渲染都会打印不同的ref对象(证明createRef每次创建新对象)console.log('当前渲染的ref对象:', inputRef);return (<div style={{ padding: 20 }}><h3>函数组件中使用createRef</h3><inputref={inputRef}type="text"placeholder="点击按钮聚焦"style={{ marginRight: 10 }}/><button onClick={handleFocus}>聚焦输入框</button><button onClick={handleLog} style={{ marginLeft: 10 }}>打印输入值</button><p ref={logRef} style={{ marginTop: 10 }}></p></div>);
}export default CreateRefInFunction;