在前端开发过程中,必然有些情况会需要dom元素进行一些节点操作,抛开原生的获取方法,本文将介绍React提供的解决方案,本文所有示例运行版本为react@16.11.0
1. ref
React16.3版本之后React.createRef() API,使用方式如下
class Home extends Component {
constructor(props){
super(props)
this.state = {
}
// ref回调方式获取
this.pRef = null
this.setCallBackRef = element => {
this.pRef = element
}
this.myNode = React.createRef()
this.myPara = React.createRef()
}
componentDidMount(){
console.log(this.myNode.current)
console.log(this.myPara.current)
// 无current
console.log(this.pRef)
}
render() {
return <div>
<Para ref={this.myPara} />
<p ref={this.setCallBackRef}>123</p>
<p ref={this.myNode}>{this.props.number}</p>
</div>
}
}
当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中被访问。
ref 的值根据节点的类型而有所不同:
- 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。即:
this.myNode.current
获取到的元素为dom - 当 ref 属性用于自定义
class
组件时,ref 对象接收组件的挂载实例作为其 current 属性。即:this.myPara.current
获取到的是组件的实例 - 函数组件不能使用ref属性,因为他们没有实例
备注:ref在componentDidMount
或 componentDidUpdate
生命周期钩子触发前更新。

可以看出,我们在挂在到自定义组件时,获取到了这个组件的实例,可以获取到它的props,context以及自定义函数,那么有意思的事情就来了,我们这时可以再父组件中调用子组件的函数来完成某些业务场景
class Para extends React.Component {
close = () => {
alert(1)
}
render(){
return <div>
<p>1</p>
</div>
}
}
class Home extends Component {
constructor(props){
super(props)
this.myPara = React.createRef()
}
render() {
return <div>
<Para ref={this.myPara} />
<button onClick={()=>this.myPara.current.close()}>close</button>
</div>
}
}
运行结果如下

这个操作可以实现有趣的功能,可以好好玩一下,特别是在业务组件里。
2. findDOMNode()
reactDom提供了一个api,可以让我们获取dom节点,不过大多数情况下不推荐使用,且在严格模式下已经被弃用。
弃用原因:findDOMNode 只返回第一个子节点,但是使用 Fragments,组件可以渲染多个 DOM 节点。findDOMNode 是一个只读一次的 API。调用该方法只会返回第一次查询的结果。如果子组件渲染了不同的节点,则无法跟踪此更改。因此,findDOMNode 仅在组件返回单个且不可变的 DOM 节点时才有效。
class Home extends Component {
constructor(props){
super(props)
this.state = {
}
// ref回调方式获取
this.pRef = null
this.setCallBackRef = element => {
this.pRef = element
}
this.myNode = React.createRef()
this.myPara = React.createRef()
}
// 获取实例化组件dom
getComponent = () => {
const node = findDOMNode(this.myPara.current)
console.log(node)
}
componentDidMount(){
console.log(this.myNode.current)
console.log(this.myPara.current)
// 无current
console.log(this.pRef)
}
render() {
return <div>
<Para ref={this.myPara} />
<p ref={this.setCallBackRef}>123</p>
<p ref={this.myNode}>{this.props.number}</p>
<button onClick={()=>this.myPara.current.close()}>close</button>
<button onClick={this.getComponent}>getNode</button>
</div>
}
}
ReactDOM下的几个api都很有趣,回头分析一下,埋个坑。
3.useRef
react@16.8版本之后,使用hook,hook提供了useRef来获取dom,注意:返回的 ref 对象在组件的整个生命周期内保持不变(current是变化的),相对React.createRef()在生命周期过程中是一直变化的。代码如下
import React, { useRef, useEffect } from 'react';
import Para from './Para'
const UseRef = () => {
const myNode = useRef(null);
const myPara = useRef(null);
useEffect(() => {
console.log(myNode.current)
console.log(myPara.current)
}, []);
return <div>
<p ref={myNode}>123</p>
<Para ref={myPara} />
</div>
}
export default UseRef;
网友评论