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è)務中每個圖表是一個封裝好的組件,(如圖一所示琐簇,標題一行和圖表是一體的蒸健,為包裝好的Chart組件)。現(xiàn)在業(yè)務中要為每個圖表都加一個CheckBox。即纵装,需要將每個圖表組件進行再次包裝征讲,將check state與chart組合成一個Component.

  • 如果checkbox位置如圖2所示,則checkBox可以作為圖表組件的children橡娄,也可以作為兄弟組件诗箍,只要調整下其位置即可。

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

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

實踐1: 屬性代理

組件結構如下汤求,state保存在Parent中,CheckBox和Chart是兄弟組件严拒。當isChecked切換狀態(tài)時扬绪,修改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>
      );
    }
  };

此處是通過包裹另外組件實現(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;
    }
  };
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末沧奴,一起剝皮案震驚了整個濱河市痘括,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滔吠,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挠日,死亡現(xiàn)場離奇詭異疮绷,居然都是意外死亡,警方通過查閱死者的電腦和手機嚣潜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門冬骚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事只冻”勇螅” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵喜德,是天一觀的道長山橄。 經常有香客問我,道長舍悯,這世上最難降的妖魔是什么航棱? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮萌衬,結果婚禮上饮醇,老公的妹妹穿的比我還像新娘。我一直安慰自己秕豫,他們只是感情好朴艰,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著混移,像睡著了一般呵晚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沫屡,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天饵隙,我揣著相機與錄音,去河邊找鬼沮脖。 笑死金矛,一個胖子當著我的面吹牛,可吹牛的內容都是我干的勺届。 我是一名探鬼主播驶俊,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼免姿!你這毒婦竟也來了饼酿?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤胚膊,失蹤者是張志新(化名)和其女友劉穎故俐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體紊婉,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡药版,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了喻犁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片槽片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡何缓,死狀恐怖,靈堂內的尸體忽然破棺而出还栓,到底是詐尸還是另有隱情碌廓,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布剩盒,位于F島的核電站谷婆,受9級特大地震影響,放射性物質發(fā)生泄漏勃刨。R本人自食惡果不足惜波材,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望身隐。 院中可真熱鬧廷区,春花似錦、人聲如沸贾铝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垢揩。三九已至玖绿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叁巨,已是汗流浹背斑匪。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锋勺,地道東北人蚀瘸。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像庶橱,于是被迫代替她去往敵國和親贮勃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容

  • React進階之高階組件 前言 本文代碼淺顯易懂苏章,思想深入實用寂嘉。此屬于react進階用法,如果你還不了解react...
    流動碼文閱讀 1,183評論 0 1
  • 高階組件是react應用中很重要的一部分枫绅,最大的特點就是重用組件邏輯泉孩。它并不是由React API定義出來的功能,...
    叫我蘇軾好嗎閱讀 888評論 0 0
  • 函數(shù)式編程撑瞧,對應的是聲明式編程棵譬,聲明式編程的本質的lambda驗算(是一個匿名函數(shù),即沒有函數(shù)名的函數(shù)预伺。Lambd...
    不安分的三好份子閱讀 1,000評論 0 1
  • 3. JSX JSX是對JavaScript語言的一個擴展語法订咸, 用于生產React“元素”,建議在描述UI的時候...
    pixels閱讀 2,806評論 0 24
  • 原文地址:React is Slow, React is Fast: Optimizing React Apps ...
    吖嚇閱讀 9,846評論 1 13