React高階組件

前段時間在工作中寫Hybrid頁面時遇到了這樣的一個場景筐乳,公司需要一系列的活動組件隘马,在每個組件注冊的時候都需要調(diào)用App端提供的一個接口。一開始也考慮了幾種方式扫步,包括mixin魔策、組件繼承以及react高階組件。但經(jīng)過了種種衡量河胎,最后選擇使用了高階組件的做法闯袒。

1、Mixins的缺點

React官方已不推薦使用Mixins的技術(shù)來實現(xiàn)代碼的重用游岳,Mixins技術(shù)有一系列的缺點政敢,首先Mixins會造成命名沖突,我們通過以下的方式來注入Mixins:

var myMixins = require('myMixins');

var Button = React.createClass({
    mixins: [myMixins],
    
    // ...
})

如果你需要注入多個mixins,其中一個是自己的胚迫,另外的可能是第三方的喷户。那有可能在兩個mixins里使用了相同名稱的方法,這會使得其中的一個不起作用访锻,而你能做的只有修改其中一個方法的名稱褪尝。另一方面,一個mixins一開始可能是非常簡單的期犬,僅僅需要實現(xiàn)某一個功能河哑,但當(dāng)業(yè)務(wù)越加的復(fù)雜,需要往其中加入更多的方法的時候龟虎,就會變得非常復(fù)雜灾馒。要深入了解mixins的缺點,可以查看官方博客遣总。

2睬罗、組件繼承

對于我自己來說這種方法以前使用的比較多,先創(chuàng)建一個BaseComponent旭斥,在其中實現(xiàn)一系列公共的方法容达,其后的每個組件都繼承于這個組件,但缺點是不夠靈活垂券,在基礎(chǔ)組件中只能實現(xiàn)一些比較固定的方法花盐,而對于每個組件的定制化會有很大的限制羡滑。

3、React高階組件

由于mixins的一系列缺點算芯,React官方也意識到使用mixins所帶來的痛點遠(yuǎn)遠(yuǎn)高于技術(shù)本身產(chǎn)生的優(yōu)點柒昏,而高階組件便可以代替mixins,而且當(dāng)深入之后它還有著更加豐富的用法熙揍。

高階組件(HOC)是React中對組件邏輯進(jìn)行重用的高級技術(shù)职祷。但高階組件本身并不是React API。它只是一種模式届囚,這種模式是由React自身的組合性質(zhì)必然產(chǎn)生的有梆。

高階函數(shù)

說到高階組件,就先得說到高階函數(shù)了意系,高階函數(shù)是至少滿足下列條件的函數(shù):

1泥耀、接受一個或多個函數(shù)作為輸入
2、輸出一個函數(shù)

在javascript這門函數(shù)為一等公民的語言中蛔添,高階函數(shù)的使用還是非常之多的痰催,像我們平時的回調(diào)函數(shù)等等,都用到了高階函數(shù)的知識迎瞧。我們先來看一個簡單的高階函數(shù)

var fun = function(x, y) {
    return x + y;
}

fun是一個函數(shù)夸溶,下面我們將整個函數(shù)作為參數(shù)傳遞給另一個函數(shù)

var comp = function(x, y, f) {
    return f(x,y);
}

驗證一下

comp(1,2,fun) // 3
高階組件定義

類比高階函數(shù)的定義,高階組件就是接受一個組件作為參數(shù)夹攒,在函數(shù)中對組件做一系列的處理蜘醋,隨后返回一個新的組件作為返回值。

我們先定義一個高階組件BaseActivity

const BaseActivity = (WrappedComponent) => {
  return class extends Component {
    render() {
      return (
        <section>
          <div>我的包裹組件</div>
          <WrappedComponent />
        </section>
        
      )
    }
  }
}

組件接受一個被包裹的組件作為參數(shù)咏尝,返回了一個經(jīng)過處理的匿名組件压语。
在其他組件中使用這個高階組件

class Example extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      width: '100%',
      height: '100%'
    }
  }

  componentWillMount() {
    if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
      return;
    } else {
      this.setState({
        width: '375px',
        height: '640px'
      })
    }
  }

  render() {
    let { width, height } = this.state;
    return (
      <div className="activity">
        <div className="activity-content" style={{ width, height }}>
          <button className="btn">參加活動</button>
        </div>
      </div>
    )
  }
}

export default BaseActivity(Example);

具體用法就是在export 組件的時候,使用BaseActivity函數(shù)來包裹這個組件编检,看下輸出的react dom內(nèi)容

image

在Example組件外面包裹了一個匿名組件胎食。

參數(shù)

既然高階組件是一個函數(shù),我們就可以向里面?zhèn)鬟f我們需要的參數(shù)

const BaseActivity = (WrappedComponent, title) => {
  return class extends Component {
    render() {
      return (
        <section>
          <div>{title}</div>
          <WrappedComponent />
        </section>
        
      )
    }
  }
}

在Example中這樣export

export default BaseActivity(Example, '這是高階組件的參數(shù)');

我們看下輸出的react dom

image

可以看到參數(shù)已經(jīng)傳遞進(jìn)去了允懂。

當(dāng)然還可以這樣用(柯里化)

const BaseActivity (title) => (WrappedComponent) => {
  return class extends Component {
    render() {
      return (
        <section>
          <div>{title}</div>
          <WrappedComponent />
        </section>
        
      )
    }
  }
}

在Example中這樣export

export default BaseActivity('這是高階組件的參數(shù)')(Example);

這種用法在ant-design的表單以及redux的connect中我們都可以看到

// ant
const WrappedDemo = Form.create()(Demo)

// redux
export default connect(mapStateToProps, mapDispatchToProps)(Counter)

高階組件還可以擴(kuò)展原組件的props屬性厕怜,如下所示:

const BaseActivity (title) => (WrappedComponent) => {
  return class extends Component {
    render() {
      const newProps = {
          id: Math.random().toString(8)
      }
      return (
        <section>
          <div>{title}</div>
          <WrappedComponent {...this.props} {...newProps}/>
        </section>
      )
    }
  }
}

看下輸出的react dom

image
高階組件的缺點

高階組件也有一系列的缺點,首先是被包裹組件的靜態(tài)方法會消失蕾总,這其實也是很好理解的粥航,我們將組件當(dāng)做參數(shù)傳入函數(shù)中,返回的已經(jīng)不是原來的組件生百,而是一個新的組件递雀,原來的靜態(tài)方法自然就不存在了。如果需要保留蚀浆,我們可以手動將原組件的方法拷貝給新的組件缀程,或者使用hoist-non-react-statics之類的庫來進(jìn)行拷貝搜吧。

結(jié)語

高階函數(shù)對于初學(xué)者來說可能不太好理解,但當(dāng)你深入其中杨凑,了解其中的原理之后滤奈,我們可以使用高階函數(shù)來完成很多的工作。

如果喜歡請關(guān)注我的Blog撩满,給個Star吧蜒程,會定期分享一些JS中的知識,^_^

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鹦牛,一起剝皮案震驚了整個濱河市搞糕,隨后出現(xiàn)的幾起案子勇吊,更是在濱河造成了極大的恐慌曼追,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汉规,死亡現(xiàn)場離奇詭異礼殊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)针史,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門晶伦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人啄枕,你說我怎么就攤上這事婚陪。” “怎么了频祝?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵泌参,是天一觀的道長。 經(jīng)常有香客問我常空,道長沽一,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任漓糙,我火速辦了婚禮铣缠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昆禽。我一直安慰自己蝗蛙,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布醉鳖。 她就那樣靜靜地躺著捡硅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辐棒。 梳的紋絲不亂的頭發(fā)上病曾,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天牍蜂,我揣著相機(jī)與錄音,去河邊找鬼泰涂。 笑死鲫竞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的逼蒙。 我是一名探鬼主播从绘,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼是牢!你這毒婦竟也來了场绿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤踪少,失蹤者是張志新(化名)和其女友劉穎哆窿,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體社搅,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡驻债,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了形葬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片合呐。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖笙以,靈堂內(nèi)的尸體忽然破棺而出淌实,到底是詐尸還是另有隱情,我是刑警寧澤猖腕,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布拆祈,位于F島的核電站,受9級特大地震影響谈息,放射性物質(zhì)發(fā)生泄漏缘屹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一侠仇、第九天 我趴在偏房一處隱蔽的房頂上張望轻姿。 院中可真熱鬧,春花似錦逻炊、人聲如沸互亮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豹休。三九已至,卻和暖如春桨吊,著一層夾襖步出監(jiān)牢的瞬間威根,已是汗流浹背凤巨。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留洛搀,地道東北人敢茁。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像留美,于是被迫代替她去往敵國和親彰檬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 在目前的前端社區(qū)谎砾,『推崇組合逢倍,不推薦繼承(prefer composition than inheritance)...
    Wenliang閱讀 77,665評論 16 125
  • 一個高階組件就是一個函數(shù),這個函數(shù)接受一個組件作為輸入景图,然后返回一個新的組件作為結(jié)果较雕,而且,返回的新組件擁有了輸入...
    DCbryant閱讀 961評論 0 0
  • React高階組件探究 在使用React構(gòu)建項目的過程中症歇,經(jīng)常會碰到在不同的組件中需要用到相同功能的情況郎笆。不過我們...
    緋色流火閱讀 2,570評論 4 19
  • 高階組件是對既有組件進(jìn)行包裝谭梗,以增強(qiáng)既有組件的功能忘晤。其核心實現(xiàn)是一個無狀態(tài)組件(函數(shù)),接收另一個組件作為參數(shù)激捏,然...
    柏丘君閱讀 3,060評論 0 6
  • 住在一個到處是木棉花的小鎮(zhèn)真好设塔,在一個慵懶的早晨或下午,不經(jīng)意間推開窗戶远舅,會驚喜的發(fā)現(xiàn)闰蛔,一樹火紅的木棉花不知何時悄...
    糖印閱讀 492評論 3 1