React.js |Refs转发 Refs获取DOM对象 Refs转发到DOM组件 在高阶组件中获取实例 Refs转发到高阶组件内部

  • ref以字符串形式出现,通过this.refs获取

    class Counter extends React.Component{
        state={count:0}
        add=()=>{this.refs.info.textContent=++this.state.count}  //获取dom对象
        render(){
            return(
                <div>
                    <button onClick={this.add}>加1</button>
                    <p ref="info">{this.state.count}</p>
                </div>
            )
        }
    } 
    
  • 创建ref对象,通过refObject.current获取

    class Counter extends React.Component{
        state={count:0}
        dom=React.createRef() //1.创建ref
        add=()=>{this.dom.current.textContent=++this.state.count}  //2.获取dom对象
        render(){
            return(
                <div>
                    <button onClick={this.add}>加1</button>
                    <p ref={this.dom}>{this.state.count}</p>
                </div>
            )
        }
    } 
    

React.js |Refs转发
Refs获取DOM对象
Refs转发到DOM组件
在高阶组件中获取实例
Refs转发到高阶组件内部

Refs转发到DOM组件

过程简述:创建ref对象,子组件接收ref

const counterRef=React.createRef()  //1.创建ref
class App extends Component {
  render() {
    //2. 接收ref并创建组件
    const Counter=React.forwardRef((props,ref)=>(
      <input ref={ref} value={props.children} type="button"/>
    ))
    return <Counter ref={counterRef}>hello</Counter>
  }
  componentDidMount(){
    console.log(counterRef.current)
  }
}

React.js |Refs转发
Refs获取DOM对象
Refs转发到DOM组件
在高阶组件中获取实例
Refs转发到高阶组件内部

总结Refs转发到DOM组件过程

  • 通过React.createRef()创建ref
  • 通过React.forwardRef()接收ref并创建组件
  • 内部组件接收ref

在高阶组件中获取实例

下面是一个简单的高阶组件:

WrapComponent.js

function wrapComponent(OriginalComponent) {
    class Extra extends React.Component {
      componentDidMount() {
        console.log('我是新来的')
      }
      render() {
        return <OriginalComponent {...this.props}/>;
      }
    }
    return Extra
}

SayHi.js

//1.导入高阶组件
import wrapComponent from './WrapComponent'
//2.原始组件
class SayHi extends React.Component{
    render(){
        return <h1>hello!{this.props.name}</h1>
    }
}
//3.导出包装后的组件
export default wrapComponent(SayHi)

App.js

//导入包装后的组件
import SayHi from './SayHi'
class App extends Component {
  render(){
    return(
      <SayHi name={'Lisa'}/>
    )
  }
}

现在获取实例:

function wrapComponent(OriginalComponent) {
    class Extra extends React.Component {
      componentDidMount() {
        console.log('我是新来的')
        console.log(this.refs.child)
      }
      render() {
        return <OriginalComponent ref="child"/>;
      }
    }
    return Extra
}

React.js |Refs转发
Refs获取DOM对象
Refs转发到DOM组件
在高阶组件中获取实例
Refs转发到高阶组件内部

Refs转发到高阶组件内部

但是不想在高阶组件中写呢?

const ref=React.createRef() //1.创建ref
class App extends Component {
  render(){
    return(
      <SayHi name={'Lisa'} ref={ref}/>
    )
  }
  //想获取被包裹的组件
  componentDidMount(){
    console.log(ref.current)
  }
}
//WrapComponent.js
function wrapComponent(OriginalComponent) {
  class Extra extends React.Component {
    componentDidMount(){
      console.log('我是新来的')
    }
    render() {
      return <OriginalComponent {...this.props}/>;
    }
  }
  return Extra
}

React.js |Refs转发
Refs获取DOM对象
Refs转发到DOM组件
在高阶组件中获取实例
Refs转发到高阶组件内部

可见并没有获取到被包裹的组件。这是因为ref 会引用最外层的容器组件(Extra),而不是内部组件。如何解决呢?通过React.forwardRef 将接收到的refs 以prop的方式传递到内部组件。现在改装一下高阶组件:

function wrapComponent(OriginalComponent) {
    class Extra extends React.Component {
      render() {
        //3.接收到外层组件的prop,解构一下
        const {forwardedRef, ...rest} = this.props;
        //4.只需把传过来的ref(forwardedRef)定义为 ref
        //  这时ref就可以挂载到被Extra包裹的子组件上了
        return <OriginalComponent ref={forwardedRef} {...rest} />;
      }
    }
  
    //1.在外层通过React.forwardRef接收传过来的ref
    //2.在这里,ref被作为常规 prop 属性传递给 Extra。现在将传过来的ref暂时储存在forwardedRef中
    return React.forwardRef((props, ref) => {
      return <Extra {...props} forwardedRef={ref} />;
    });
}

React.js |Refs转发
Refs获取DOM对象
Refs转发到DOM组件
在高阶组件中获取实例
Refs转发到高阶组件内部

只在使用 React.forwardRef 定义组件的时候,参数 ref才会存在。常规函数和 class 组件不接收 ref 参数,且 props 中也不存在 ref

参考: