在 React 中,直接操作 DOM 通常不被推荐(应优先考虑状态驱动 UI),但在某些特定场景下(如管理焦点、触发动画、集成第三方库)需要访问真实的 DOM 元素。React 提供了 ref 来实现这一需求。
以下是几种获取组件对应 DOM 元素的方法:
1. 使用 useRef Hook (函数组件推荐)
useRef 是函数组件中创建 ref 的标准方式。它返回一个可变的 ref 对象,其 .current 属性指向 DOM 元素。
基本用法:
import React, { useRef, useEffect } from 'react';
function TextInput() {
const inputRef = useRef(null);
const focusInput = () => {
// 访问真实 DOM 元素并调用其方法
inputRef.current.focus();
};
return (
<div>
{/* 将 ref 绑定到 DOM 元素 */}
<input ref={inputRef} type="text" />
<button onClick={focusInput}>聚焦输入框</button>
</div>
);
}
结合 useEffect 在挂载后操作 DOM:
function AutoFocusInput() {
const inputRef = useRef(null);
useEffect(() => {
// 组件挂载后自动聚焦
inputRef.current.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
2. 使用 createRef (类组件)
在类组件中,可以使用 React.createRef() 创建 ref。
class MyComponent extends React.Component {
constructor(props) {
super(props);
// 创建 ref
this.myRef = React.createRef();
}
componentDidMount() {
// 访问 DOM 元素
this.myRef.current.focus();
}
render() {
return <input ref={this.myRef} type="text" />;
}
}
3. 回调 Refs (更灵活的控制)
回调 ref 允许你获得对 ref 创建和销毁的完全控制。当组件挂载时,React 会调用回调函数并传入 DOM 元素;卸载时传入 null。
function CustomTextInput() {
let inputElement;
const setRef = (element) => {
inputElement = element;
// 可在此处执行其他逻辑
};
const focus = () => {
inputElement.focus();
};
return (
<div>
<input type="text" ref={setRef} />
<button onClick={focus}>聚焦</button>
</div>
);
}
注意:如果将内联函数作为
ref回调,React 会在更新时调用两次(先传null,再传 DOM 元素)。为避免性能问题,建议使用useCallback或类属性语法稳定函数引用。
4. 转发 Ref (React.forwardRef) 获取子组件 DOM
默认情况下,ref 不能用于函数组件。若想让父组件访问子组件内部的 DOM 元素,需使用 React.forwardRef。
// 子组件:使用 forwardRef 暴露内部 DOM
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="fancy-button">
{props.children}
</button>
));
// 父组件:通过 ref 获取子组件内的 button 元素
function Parent() {
const buttonRef = useRef(null);
const clickButton = () => {
buttonRef.current.click(); // 触发子组件按钮的点击
};
return (
<div>
<FancyButton ref={buttonRef}>点击我</FancyButton>
<button onClick={clickButton}>通过父组件点击</button>
</div>
);
}
5. 使用 findDOMNode (已废弃,不推荐)
在旧版 React 中,findDOMNode 可用于查找组件对应的 DOM 节点。但该方法:
- 已被废弃,不推荐在新代码中使用。
- 不支持严格模式。
- 无法与函数组件或
React.memo一起使用。
// ❌ 不推荐
// const domNode = findDOMNode(this);
总结对比
| 方法 | 适用场景 | 备注 |
|---|---|---|
useRef | 函数组件访问自身 DOM | 最常用,推荐 |
createRef | 类组件访问自身 DOM | 类组件标准方式 |
| 回调 Refs | 需要精确控制 ref 生命周期 | 更灵活,但稍复杂 |
forwardRef | 父组件访问子组件内部 DOM | 解决 ref 透传问题 |
findDOMNode | ❌ 已废弃 | 避免使用 |
注意事项
- 不要过度使用 ref:优先通过 state 和 props 控制组件行为。
- ref 的值在渲染期间不可变:
useRef返回的对象在整个组件生命周期中保持不变。 - DOM 节点在挂载后才可用:确保在
useEffect或componentDidMount后再访问ref.current。 - TypeScript 中需正确声明类型:
const inputRef = useRef<HTMLInputElement>(null);
掌握这些方法,就能在必要时安全、有效地访问和操作 DOM 元素。
THE END


