React HOC的兩種實踐

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進行修改。能力更強,但風險也更高。

不能保證完整的子組件樹被解析, 以及靜態(tài)方法不會被繼承。

實踐

需求簡介:

目前頁面中已有多個圖表組件(單一維度的數(shù)據(jù)統(tǒng)計折線圖),目前想為每個圖表添加checkBox,可以交叉其他維度進行統(tǒng)計。

圖1,2,3

需求分析:

  • 目前業(yè)務(wù)中每個圖表是一個封裝好的組件,(如圖一所示,標題一行和圖表是一體的,為包裝好的Chart組件)。現(xiàn)在業(yè)務(wù)中要為每個圖表都加一個CheckBox。即,需要將每個圖表組件進行再次包裝,將check state與chart組合成一個Component.

  • 如果checkbox位置如圖2所示,則checkBox可以作為圖表組件的children,也可以作為兄弟組件,只要調(diào)整下其位置即可。

  • 倘若checkBox要如圖3,放在title和圖表中間,則需要將CheckBox作為Chart的children才能插入到該位置,否則是沒有空間放checkbox。如何才能以較低成本,給十來個Chart組件都添加CheckBox這個Children呢?此時就只能通過Hoc修改其props.children來實現(xiàn)了

按照上圖所示布局,我們通過兩種HOC方式都來實踐下:

實踐1: 屬性代理

組件結(jié)構(gòu)如下,state保存在Parent中,CheckBox和Chart是兄弟組件。當isChecked切換狀態(tài)時,修改Chart對應(yīng)的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>
      );
    }
  };

此處是通過包裹另外組件實現(xiàn)的,也可以直接修改props.chilren = YourComponent實現(xiàn)。

實踐2:渲染劫持

通過繼承WrappedComponent,獲取其elementTree, 根據(jù)原props中的參數(shù),符合條件的,對其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;
    }
  };
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • React進階之高階組件 前言 本文代碼淺顯易懂,思想深入實用。此屬于react進階用法,如果你還不了解react...
    流動碼文閱讀 1,227評論 0 1
  • 高階組件是react應(yīng)用中很重要的一部分,最大的特點就是重用組件邏輯。它并不是由React API定義出來的功能,...
    叫我蘇軾好嗎閱讀 974評論 0 0
  • 函數(shù)式編程,對應(yīng)的是聲明式編程,聲明式編程的本質(zhì)的lambda驗算(是一個匿名函數(shù),即沒有函數(shù)名的函數(shù)。Lambd...
    不安分的三好份子閱讀 1,251評論 0 1
  • 3. JSX JSX是對JavaScript語言的一個擴展語法, 用于生產(chǎn)React“元素”,建議在描述UI的時候...
    pixels閱讀 2,971評論 0 24
  • 原文地址:React is Slow, React is Fast: Optimizing React Apps ...
    吖嚇閱讀 10,020評論 1 13

友情鏈接更多精彩內(nèi)容