获取react中高阶组件方法
阅读原文时间:2023年07月08日阅读:2

什么是高阶组件?

高阶组件就是接受一个组件作为参数并返回一个新组件的函数。这里需要注意高阶组件是一个函数,并不是组件,这一点一定要注意。同时这里强调一点高阶组件本身并不是 React API。它只是一种模式,这种模式是由React自身的组合性质必然产生的。更加通俗的讲,高阶组件通过包裹(wrapped)被传入的React组件,经过一系列处理,最终返回一个相对增强(enhanced)的 React 组件,供其他组件调用。

react中获取的ref是什么?

  • 如果ref写在组件上,那么获取的是 组件的实例对象;
  • 如果ref写在组件内的标签上(div,span等),获取的相应的DOM节点那么可知本文中获取的高阶组件的ref所指的是组件的实例对象即 子组件的this

获取方式:

@withRouter
export default class childComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    const { getInstance } = props;
    if (typeof getInstance === 'function') {
      getInstance(this); // 在这里把this暴露给`parentComponent`
    }
  }
  render() {
    return (<div>this is childComponent</div>)
  }
}
@withRouter
export default class parentComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  render () {
    return (
     <childComponent
       ref={(withRouter) => { this.childCpWrapper = withRouter; }}  // 这里获取的是`withRouter`组件,一般没啥用,这里写出来只是为了对比
       getInstance={(childCp) => { this.childCp = childCp; }} // 这里通过`getInstance`传一个回调函数接收`childComponent`实例即可
    />
    );
  }
 }

下面将上面的方法优化一下,单独写一个类来获取

// 只做一件事,把`WrappedComponent`回传个`getInstance`(如果有的话)
export default (WrappedComponent) => {
  return class withRef extends Component {
    static displayName = `withRef(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
    render() {
      // 这里重新定义一个props的原因是:
      // 你直接去修改this.props.ref在react开发模式下会报错,不允许你去修改
      const props = {
        ...this.props,
      };
      const { getInstance } = props;
      if (typeof getInstance === 'function') {
        // 在这里把getInstance赋值给ref,
        // 传给`WrappedComponent`,这样就getInstance能获取到`WrappedComponent`实例
        props.ref = getInstance;
      }
      return (
        <WrappedComponent {...props} />
      );
    }
  };
};

// 如何使用?
@withRouter
@withRef  // 这样使用是不是方便多了,注意:这句必须写在最接近`childComponent`的地方
export default class childComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  render() {
    return (<div>this is childComponent</div>)
  }
}
@withRouter
export default class parentComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  render () {
    return (
     <childComponent
       // 这里获取的是`withRouter`组件,一般没啥用,这里写出来只是为了对比
       ref={(withRouter) => { this.childCpWrapper = withRouter; }}
      // 这里通过`getInstance`传一个回调函数接收`childComponent`实例即可
       getInstance={(childCp) => { this.childCp = childCp; }}
    />
    );
  }
 }