React DOM操作

转自 https://itbilu.com/javascript/react/4JZnZhDcl.html

注:getDOMNode方法已被findDOMNode()替代

大多数情况下,我们并不需要直接操作真实的DOM,React 的虚拟DOM足以满足创建用户界面的需要。而在极少数情况下,我们又不得不去操作底的DOM。为了和浏览器交互,我们需要获取对DOM节点的引用,React 提供了一个访问受自身控制的DOM节点(已挂载组件)的方法getDOMNode,通过这个方法我们可以在组件挂载后访问底层 DOM。

refs属性

受控的DOM节点是指由在React 组件挂载后,React 组件由生成的DOM节点。要访问这些DOM节点,首先需要获取对这些节点的引用,这时我们需要为组件设置一个ref属性。ref可以是一个字符串,可用于任何由render()方法返回的组件实例。ref做为字符串时,相当于一个组件ID,所以其值必须是唯一的。

设置该refs属性后,我们就可以在组件内部通过this.refs或通过findDOMNode()查找组件生成的DOM。

在render()方法中设置refs属性:

<input type="text" ref="myInput" />
设置refs属性可以通过this.refs获取对组件的引用:

this.refs.myInput
或者使用findDOMNode查找DOM:

React.findDOMNode(this.refs.myInput)

ref 回调属性

ref属性可是一个回调函数,该函数会在组件挂载后立即执行,被引用的组件会做为参数传入回调函数中:

<input ref={ function(component){ React.findDOMNode(component).focus();} } />

findDOMNode方法与getDOMNode方法

findDOMNode是ReactDOM类库提供的一个类方法。该方法可以在组件内部或外部获取对组件生成的底层DOM的引用。

getDOMNode是React组件的实例方法,该方法可以获取组件实例生成的DOM引用。

findDOMNode和getDOMNode方法都会返回一个DOM元素(DOMElement),但findDOMNode方法找不到元素生成的DOM元素时,可能会返回NULL。

示例:使用findDOMNode或getDOMNode访问底层DOM:

var MyInput = React.createClass({
  handleClick: function() {
    // 使用getDOMNode方法访问底层的API
    this.refs.myInput.getDOMNode().focus();
  },
  componentDidMount: function() {
    // 使用findDOMNode方法访问底层的API
    ReactDOM.findDOMNode(this.refs.myInput).value = 'itbilu.com';
  },
  render: function() {
    return <input type="text" ref="myInput" />;
  }
});

ReactDOM.render(
  <MyInput />,
  document.getElementById('example')
);

内部访问与外部访问

上面介绍了通过通过组件的refs属性访问组件生成的底层DOM,使用refs属性访问组件,是组件的内部访问。

在实际应中,可能还会外部访问组件。外部访问组件生成的DOM,要通过ReactDOM.render()方法返回的组件实例获取对组件的引用:

var MyInput = React.createClass({
  render: function() {
    return <input type="text" />;
  }
});

var myInput = ReactDOM.render(
  <MyInput />,
  document.getElementById('example')
);

// 使用findDOMNode()方法外部访问组件
ReactDOM.findDOMNode(myInput).value = 'itbilu.com';

// 使用getDOMNode()方法外部访问组件
myInput.getDOMNode().focus();

可访问DOM的组件生命周期

要访问底层DOM要在DOM创建完成后,即:组件挂载完成后。componentDidMount并不是底层DOM的唯一的访问环境,在componentDidMount挂载完成后,及组件生命周期的存在期、销毁&清理期都可以访问。

<think>我们正在讨论React中的DOM操作。根据用户提供的引用,我们可以总结出React操作DOM的几种方式: 1. 使用Refs(通过`useRef` Hook或回调Ref)来获取DOM节点引用 2. 通过事件对象(event)获取事件目标(EventTarget) 3. 使用原生JavaScript DOM选择器(如document.querySelector) 4. 使用ReactDOMfindDOMNode方法(不推荐) 5. 通过第三方库(如jQuery)操作DOM(不推荐,除非必要) 用户意图是查找ReactDOM操作指南及相关问题解决方案。因此,我们将围绕这些方法展开,并注意引用用户提供的参考资料。 回答结构: 1. 引言:简要说明在React操作DOM的必要性和注意事项 2. 具体方法:详细介绍每种方法,并给出示例代码 3. 最佳实践:推荐使用的方法和注意事项 4. 常见问题及解决方案 5. 相关问题 注意:在React中,直接操作DOM应该谨慎使用,因为它可能绕过React的虚拟DOM机制,导致状态不一致或性能问题。推荐优先使用React的声明式方式。</think>### React DOM操作指南及问题解决方案 在React开发中,虽然官方推荐使用虚拟DOM进行状态驱动更新,但某些场景仍需直接操作真实DOM。以下是基于引用资料的完整操作指南: #### 一、React操作DOM的5种方式 1. **使用Refs(推荐方式)** - 函数组件示例: ```jsx import { useRef } from 'react'; function MyComponent() { const inputRef = useRef(null); const handleClick = () => { inputRef.current.focus(); // 直接操作DOM console.log(inputRef.current.value); }; return ( <div> <input ref={inputRef} /> <button onClick={handleClick}>聚焦</button> </div> ); } ``` - **适用场景**:表单控件聚焦、获取元素尺寸、集成第三方DOM库[^4] 2. **事件对象获取EventTarget** ```jsx const handleChange = (e) => { console.log(e.target.value); // 直接访问事件目标元素 e.target.classList.add('active'); }; return <input onChange={handleChange} />; ``` **优势**:无需额外ref声明,适合简单操作[^1] 3. **原生DOM选择器(慎用)** ```jsx const handleClick = () => { const element = document.getElementById('myElement'); element.style.backgroundColor = 'red'; }; return <button onClick={handleClick}>变色</button>; ``` **风险**:可能绕过React更新机制导致状态不同步[^2] 4. **findDOMNode(不推荐)** ```jsx import ReactDOM from 'react-dom'; class MyComponent extends React.Component { handleClick = () => { const domNode = ReactDOM.findDOMNode(this); // 获取组件根DOM domNode.style.border = '1px solid red'; }; render() { /* ... */ } } ``` **缺点**:已过时API,无法用于函数组件[^3] 5. **Ref回调函数(类组件适用)** ```jsx class MyComponent extends React.Component { setRef = (element) => { this.myRef = element; // 手动存储DOM引用 }; componentDidMount() { this.myRef.style.color = 'blue'; } render() { return <div ref={this.setRef}>内容</div>; } } ``` **适用场景**:需要精细控制DOM的生命周期[^2] #### 二、DOM操作最佳实践 1. **优先使用Refs**:相比原生DOM操作更符合React设计哲学 2. **避免在render中操作**:应在`useEffect`或生命周期方法中执行 3. **虚拟DOM冲突处理**: ```jsx useEffect(() => { // DOM操作放在此处 const node = ref.current; node.addEventListener('click', handler); return () => node.removeEventListener('click', handler); // 清理副作用 }, []); ``` #### 三、常见问题解决方案 1. **Ref获取null值** - **原因**:在DOM挂载前访问ref - **解决**:在`useEffect`或`componentDidMount`中操作 ```jsx useEffect(() => { if (inputRef.current) { inputRef.current.focus(); } }, []); ``` 2. **动态元素操作失效** - **场景**:操作条件渲染的DOM元素 - **方案**:使用`useEffect`依赖项追踪变化 ```jsx const [show, setShow] = useState(false); useEffect(() => { if (show && modalRef.current) { modalRef.current.scrollIntoView(); } }, [show]); // show变化时触发 ``` 3. **第三方库集成冲突** - **问题**:jQuery修改DOM导致React状态不同步 - **方案**:隔离操作区域 + 强制更新 ```jsx const forceUpdate = useReducer(() => ({}))[1]; useEffect(() => { $('#external-widget').on('change', () => { forceUpdate(); // 手动同步状态 }); }, []); ``` 4. **性能优化** - **问题**:频繁DOM操作导致卡顿 - **方案**: - 使用`requestAnimationFrame`批量操作 ```jsx const animate = () => { elementRef.current.style.transform = `translateX(${pos}px)`; requestAnimationFrame(animate); }; ``` - 虚拟列表技术(如`react-window`) > **核心原则**:在React中,DOM操作应是*最后的选择*而非首选方案。优先考虑通过状态驱动UI更新,仅在集成第三方库、媒体控制等场景使用直接DOM操作[^1][^4]。 --- ### 相关问题 1. 如何在React中使用Refs管理视频播放器的播放状态? 2. React Portals与常规DOM操作有何性能差异? 3. 使用useRef时如何避免内存泄漏问题? 4.React StrictMode下操作DOM有哪些额外限制? 5. 如何测试包含DOM操作React组件?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值