React HOC的两种实践

作者: RichardBillion | 来源:发表于2019-12-17 18:45 被阅读0次

    HOC简介

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

    属性代理(Props Proxy)

    • 操作props
    • 抽象state
    • 获取ref
    • 用其他组件包裹(功能集成/样式包裹)

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

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

    反向继承(Inheritance Inversion)

    • 渲染劫持 render hijacking
    • 操纵state

    使用姿势常常是这样的:

    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

    需求分析:

    • 目前业务中每个图表是一个封装好的组件,(如图一所示,标题一行和图表是一体的,为包装好的Chart组件)。现在业务中要为每个图表都加一个CheckBox。即,需要将每个图表组件进行再次包装,将check state与chart组合成一个Component.

    • 如果checkbox位置如图2所示,则checkBox可以作为图表组件的children,也可以作为兄弟组件,只要调整下其位置即可。

    • 倘若checkBox要如图3,放在title和图表中间,则需要将CheckBox作为Chart的children才能插入到该位置,否则是没有空间放checkbox。如何才能以较低成本,给十来个Chart组件都添加CheckBox这个Children呢?此时就只能通过Hoc修改其props.children来实现了

    按照上图所示布局,我们通过两种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;
        }
      };
    

    相关文章

      网友评论

        本文标题:React HOC的两种实践

        本文链接:https://www.haomeiwen.com/subject/bhlenctx.html