Web 前端开发 让前端飞

React HOC的两种实践

2019-12-17  本文已影响0人  RichardBillion

HOC简介

HOC全称为High Order Component即高阶组件, 其使用姿势通常有两种:

属性代理(Props Proxy)

简而言之: 修改传入组件的props.
使用姿势常常是这样的:

const ppHoc = WrappedComponent => class extends React.Component {
    render() {
        // 此处可以修改props,或者注入state,
        // 总之对WrappedComponent而言就是修改了props
        return  <WrappedComponent {...this.props} />
    }
}

反向继承(Inheritance Inversion)

使用姿势常常是这样的:

const iiHoc = WrappedComponent => class extends WrappedComponent{
    render() {
        const elementTree = super.render();
        const { props } = elementTree;
        // 可以修改props
        const newProps = {aa: 1};

        return React.cloneElement(elementTree, {...props, ...newProps}, elementsTree.props.children)
    }
}

继承该组件,可基于其elementTree进行修改。能力更强,但风险也更高。

不能保证完整的子组件树被解析, 以及静态方法不会被继承。

实践

需求简介:

目前页面中已有多个图表组件(单一维度的数据统计折线图),目前想为每个图表添加checkBox,可以交叉其他维度进行统计。

图1,2,3

需求分析:

按照上图所示布局,我们通过两种HOC方式都来实践下:

实践1: 属性代理

组件结构如下,state保存在Parent中,CheckBox和Chart是兄弟组件。当isChecked切换状态时,修改Chart对应的props.

Parent
    CheckBox
    Chart

主要代码如下

const interHoc = WrappedComponnet =>
  class extends React.Component {
    state = {
      isChecked: false,
    };

    render() {
      const { isChecked } = this.state;
      let chartProps = { ...this.props };

      //  修改props
      const {
        formatParams: { dims = [] },
      } = chartProps;
      const GENDER_TYPE = 'predicted_gender';

      if (isChecked && !dims.includes(GENDER_TYPE)) {
        chartProps.formatParams.dims = [GENDER_TYPE].concat(dims);
      } else {
        chartProps.formatParams.dims = dims.filter(d => d !== GENDER_TYPE);
      }

      return (
        <div>
          <CheckBox
            checked={isChecked}
            onChange={e => this.setState({ isChecked: e.target.value })}
          >
            交叉性别维度
          </CheckBox>
          <WrappedComponnet {...chartProps} />
        </div>
      );
    }
  };

此处是通过包裹另外组件实现的,也可以直接修改props.chilren = YourComponent实现。

实践2:渲染劫持

通过继承WrappedComponent,获取其elementTree, 根据原props中的参数,符合条件的,对其props和props.children进行修改。

通过继承可以直接修改elementTree(修改其props和children)显然能力范围是更强大的,但风险也更高,能不用就不用吧。

const interHoc = WrappedComponent =>
  class extends WrappedComponent {
    state = {
      isChecked: false,
    };

    render() {
      const { isChecked } = this.state;

      const elementTree = super.render();

      const interCom = (
        <Checkbox
          checked={isChecked}
          onChange={e => this.setState({ isChecked: e.target.checked })}
        >
          交叉性别维度
        </Checkbox>
      );

      // 修改props
      const {
        props: {
          formatParams: { dims = [] },
        },
      } = elementTree;

      const GENDER_TYPE = 'predicted_gender';

      elementTree.props.children = interCom;
      if (isChecked && !dims.includes(GENDER_TYPE)) {
        elementTree.props.formatParams.dims = [GENDER_TYPE].concat(dims);
      } else {
        elementTree.props.formatParams.dims = dims.filter(
          i => i !== GENDER_TYPE,
        );
      }

      return elementTree;
    }
  };
上一篇 下一篇

猜你喜欢

热点阅读