- ref生成的是一个指针,指向了真实的DOM,
- ref作用:是组件实例对象中的一个属性,值是一个对象,只需要给VDOM添加ref属性即可生成ref的指向,指向该DOM,类似于原生js中通过id获取节点。
何时使用Refs
下面有一些正好使用refs的场景:
- 处理foucs、文本选择或媒体播放
- 触发强制动画
- 集成第三方DOM库
- 如果可以通过声明式实现,就尽量避免使用refs。
- 不要过度使用refs。
- 你可能首先会想到在你的应用程序中使用refs来更新组件。如果是这种情况,请花一点时间,更多的关注在组件层中使用state。在组件层中,通常较高级别的state更为清晰。
使用Ref注意以下三点
- Ref所指向的节点可以是dom节点,也可以是类组件。
- 但是Ref属性指向的节点不能是函数组件(无状态组件)
- 因为我们通过ref获得的组件,包含了生命周期和state,因此ref所指向的组件不可以是函数组件
字符串形式的ref
- 直接修改了真实节点去做操作。可以给每个元素添加ref属性,refs里就存了相应的节点。但不要过多使用。
- 该形式是把真实节点存到了refs身上
export default class App extends Component {
render() {
console.log(this)
return (
<div>
<h1 onClick={this.changeDiv}>这是最上层组件</h1>
<div ref="nh">你好</div>
</div>
)
}
changeDiv =() => {
this.refs.nh.innerHTML="hello"
}
}
回调函数形式的ref
- 在初始化的时候或更新组件就会调用该回调函数,由React调用,回调函数接收一个形参,形参就是当前节点对象,并且这个形参是一个真是节点。我们将得到的节点对象挂载到组件实例对象上。
- 该形式是把真是节点存到了组件实例对象的属性上,没有存到refs上。
export default class AppFn extends Component {
render() {
return (
<div>
<h1 onClick={this.hande}>这是顶层组件</h1>
<div ref={c => this.myEle = c}>你好</div>
</div>
)
}
hande=()=>{
this.myEle.style.background="#f00"
console.log(this)
}
}
- 官方指出,如果ref回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数null,然后第二次会传入参数DOM元素。这是因为在每次渲染时会创建一个新的函数实力,所以React清空旧的ref并设置新的。
- 为了保证更新之后得到的是更新之后的dom所以会先将该回调函数的参数赋值成null,依次保证每次都将之前的清除掉了。
- 通过ref的回调函数定义成class的绑定函数的方式可以避免上述问题,到那时大多数情况下它是无关紧要的。
React.createRef()
注意:
- 一个React.createRef()只能存一个标记,把该标记作为组件实例对象的属性,与ref进行关联。
- 想要读取节点,必须通过current
export default class AppFn extends Component {
myRef=React.createRef();
render() {
return (
<div>
<h1 onClick={this.hande}>这是1顶层组件,点击我有惊喜</h1>
<div ref={this.myRef}>你好</div>
</div>
)
}
hande=()=>{
this.myRef.current.style.backgroundColor="#fcc"
}
}
forwardRef(作用:用来访问子组件的节点)
- 通过React16.3中的forwarding refs可以使得在负组件中可以得到子组件的dom节点。
- forwarding refs中提供了一个React.forwardRef()方法来创建组件,在React.forwardRef的方法中传递了参数ref,通过这个ref可以指向具体的某一个dom节点。
- 具体的指向流程为:
- 父组件myRef——React.forwardRef中的实参——通过forwardRef方法创建的子组件中的Ref——指向子组件中的某一个don节点。