1、React中的ref是什么
ref是React提供的用来操纵React组件实例或者DOM元素的接口
2、ref的使用里程
在React v16.3 之前,ref 通过字符串(string ref)或者回调函数(callback ref)的形式进行获取,在v16.3 中,经0017-new-create-ref 提案引入了新的React.createRef API。
ref通过字符串的形式将要被移除,通过回调函数这个方式也不推荐,最好是使用React.createRef方法。
3、ref的使用
对于字符串是形式的使用和回调函数方式的使用就不写了。
在这里重点学习第三种方式 React.createRef(),先说一下 React.createRef()的原理。
在react源码中ReactRef的代码如下:
import type {RefObject} from 'shared/ReactTypes';
export function createRef(): RefObject {
const refObject = {
current: null,
};
return refObject;
}
这个源码很简单,就只是创建了一个对象并返回出来了。当使用 this.value = React.createRef()这个时,就是将这个返回的对象赋值给这个定义的变量。此时的this.value={current:null},为以后的真实DOM和类的实例的赋值奠定基础。
如果在类组件上添加ref属性的话,ref.current给的是类的实例(new 类名);如果在原生dom中加了ref属性,这个ref.current指向的原生的真实的dom。
(1)在类组件中使用REF
import React from 'react';
import ReactDom from 'react-dom';
class RefUseByClass extends React.Component{
constructor(props){
super(props);
this.classInputValue = React.createRef();
}
render(){
return(
<input ref={this.classInputValue}/>
)
}
}
class GetClassInputFocus extends React.Component{
constructor(props){
super(props);
this.getFocusInput = React.createRef();
}
getFocus =(event)=>{
//所以在这里,this.getFocusInput.current就是子组件的实例(new RefUseByClass),
//而子组件实例中返回的input也有ref,而这个ref指向的是真实的input这个dom结构,
//所以说 this.getFocusInput.current.classInputValue.current获取到的是input,
// 进而对这个input框进行操作
this.getFocusInput.current.classInputValue.current.focus();
}
render(){
return(
<React.Fragment>
//在这个父组件中调用子组件,当父组件进行render的时候,是将子组件的实例赋给了ref.current属性
<RefUseByClass ref={ this.getFocusInput}/>
<button onClick={this.getFocus}>类组件使用ref实现点击按钮输入框聚焦</button>
</React.Fragment>
)
}
}
ReactDom.render(
<GetClassInputFocus/>,
document.getElementById('root')
)

(2)在函数组件中使用ref
import React from 'react';
import ReactDom from 'react-dom';
//在这里使用函数组件,注意查看不同之处
function RefUseByClass(props,ref){
return(
<input ref={ref}/>
)
}
// React.forwardRef() 实现ref的转发
// 因为函数组件没有实例,函数一执行完就销毁了,而ref制定的是原生dom或者类的实例,所以这个函数组件是不能给定ref属性
// 如果想要给函数组件添加一个ref属性的话,就需要到了React.forwardRef()这个转发站
//将函数组件传递给这个React.forwardRef()转发站,返回的是一个封装好子组件的类组件,
//当在父组件中进行render()的时候 <ForwardRef > 组件就会执行这个返回来的类组件,
//在这个执行类组件是这个子组件也开始运行,并将子组件里的返回的真实的dom返回给ref,
//所以在点击函数getFocus里 this.getFocusInput.current指的是子组件中真实的dom,即input框。
let ForwardRef = React.forwardRef(RefUseByClass);
class GetClassInputFocus extends React.Component{
constructor(props){
super(props);
this.getFocusInput = React.createRef();
}
getFocus =(event)=>{
this.getFocusInput.current.focus();
}
render(){
return(
<React.Fragment>
<ForwardRef ref={ this.getFocusInput}/>
<button onClick={this.getFocus}>函数组件使用ref实现点击按钮输入框聚焦</button>
</React.Fragment>
)
}
}
ReactDom.render(
<GetClassInputFocus/>,
document.getElementById('root')
)

对比一下下面的代码就知道 React.forwardRef 是怎么个意思了:
import React from 'react';
import ReactDom from 'react-dom';
function RefUseByClass(props,ref){
return(
<input ref={ref}/>
)
}
// 方式一
function forwardRef( func ){
return class extends React.Component{
render(){
return func(this.props,this.props. ref2)
}
}
}
// 方式二
// function forwardRef( func ){
// return props=>func( props,props.ref2)
// }
let ForwardRef = forwardRef(RefUseByClass);
class GetClassInputFocus extends React.Component{
constructor(props){
super(props);
this.getFocusInput = React.createRef();
}
getFocus =(event)=>{
this.getFocusInput.current.focus();
}
render(){
return(
<React.Fragment>
<ForwardRef ref2={ this.getFocusInput}/>
<button onClick={this.getFocus}>函数组件使用ref实现点击按钮输入框聚焦</button>
</React.Fragment>
)
}
}
ReactDom.render(
<GetClassInputFocus/>,
document.getElementById('root')
)
自己的学习记录,如果有误,请指出,谢谢!