react之高階組件(HOC Higher-Order Components)

定義:參數(shù)為組件的函數(shù)
功能: 為原始組件注入props (變量 方法)

定義

const EnhancedComponent = higherOrderComponent(WrappedComponent);

我們平時在react中編寫和使用的組件模式:
接收props-> 通過component -> 輸出UI
高階組件的模式:
接收componentA -> 通過HOC(純函數(shù) 無副作用) -> 輸出新的componentB

HOC 并不是一個新的React Api,而是基于React的組合特性而形成的一種設計模式
具體而言,高階組件是參數(shù)為組件,返回值為新組件的函數(shù)

當兩個組件業(yè)務邏輯一樣,渲染的結果數(shù)據(jù)源不一致,(以前是用mixins),我們需要把業(yè)務邏輯抽象,在一個地方定義這個業(yè)務邏輯,在各個組件之間共享,這就是高階組件.

使用原則

1.HOC 不要修改傳入的組件, 采用組合的方式

官方文檔多次強調: HOC和WrappedComponent的交互僅僅通過props 這樣用的好處

1.替換HOC(修改業(yè)務邏輯)變得很容易,只需要提供相同的props(更改數(shù)據(jù)源很容易).

2.對包裹組件類型無要求, 適用于class 組件和函數(shù)組件

  1. HOC和包裹組件之間 HOC和HOC 之間都可以任意組合

HOC 在 React 的第三方庫中很常見煤蹭,例如 Redux 的 connect 往組件注入props

HOC 與容器組件模式之間有相似之處箭窜。容器組件擔任分離將高層和低層關注的責任忍些,由容器管理訂閱和狀態(tài)撬统,并將 prop 傳遞給處理渲染 UI缝呕。HOC 使用容器作為其實現(xiàn)的一部分两曼,你可以將 HOC 視為參數(shù)化容器組件

2.盡量提供和包裹組件一樣的props

HOC自己的狀態(tài)不要透傳給包裹組件,當我們要替換HOC的時候更加容易

render() {  
// extraProp 為當前HOC狀態(tài) 不需要透傳給WrappedComponent 需要篩選出來 
const { extraProp, ...passThroughProps } = this.props;   
const injectedProp = someStateOrInstanceMethod;   
// 其他 props 全部透傳給 WrappedComponent 
return ( <WrappedComponent injectedProp={injectedProp} {...passThroughProps} /> ); 
}

3.最大組合性

單參數(shù)HOC

const NavbarWithRouter = withRouter(Navbar);

多參數(shù)HOC

const CommentWithRelay = Relay.createContainer(Comment, config);

最常見HOC 高階函數(shù)

高階函數(shù) React Redux 的 connect 函數(shù) 一個返回高階組件的高階函數(shù)皂甘!

//原始寫法 
const ConnectedComment = connect(commentSelector, commentActions)(CommentList);   
// 翻譯過來 
// connect 是一個高階函數(shù),它的返回值為另外一個函數(shù) 
const enhance = connect(commentListSelector, commentListActions); 
// 返回值為 HOC合愈,它會返回已經(jīng)連接 Redux store 的組件 
const ConnectedComment = enhance(CommentList);

connet高階函數(shù)返回一個單參數(shù)的高階組件具有 component -> component特性,輸出類型與輸入類型相同的函數(shù)很容易組合,對于單參數(shù)的高階組件,HOC可以和HOC組合

const EnhancedComponent = withouter(connet(store)(componentA))

組合函數(shù) compose

// 原始寫法
const EnhancedComponent = withouter(connet(store)(componentA))  
 // ... 你可以編寫組合工具函數(shù) 
// compose(f, g, h) 等同于 (...args) => f(g(h(...args))) 
// 把輸出型==輸入型的函數(shù)(HOC)都組合起來 
const enhance = compose([  withouter, connet(store) ])   
const EnhancedComponent = enhance(componentA)

很多庫都提供compose 函數(shù) Composes functions from right to left.

右邊方法的出參 -> 作為左邊方法的入?yún)?(輸出類型與輸入類型相同)

1.redux compose 專為中間件設計 compose(applyMiddleware(thunk), DevTools.instrument())
2.lodash flow 和 flowright 為方法調用順序設計

裝飾器 Decorators

文檔鏈接: https://www.tslang.cn/docs/handbook/decorators.html

// 也可以再進一步寫為裝飾器模式 
@withouter @connet(store) componentA

注意事項

不要在 render 方法中使用 HOC

render() {  
// 每次調用 render 函數(shù)都會創(chuàng)建一個新的 EnhancedComponent 
// EnhancedComponent1 !== EnhancedComponent2 
const EnhancedComponent = enhance(MyComponent); 
// 這將導致子樹每次渲染都會進行卸載叮贩,和重新掛載的操作! 
return <EnhancedComponent />; 
}

會導致EnhancedComponent頻繁的掛載,卸載,這不僅僅是性能問題 - 重新掛載組件會導致該組件及其所有子組件的狀態(tài)丟失佛析。

靜態(tài)方法記得復制

// 定義靜態(tài)函數(shù) 
WrappedComponent.staticMethod = function() {/*...*/} 
// 現(xiàn)在使用 HOC 
const EnhancedComponent = enhance(WrappedComponent);   
// 增強組件沒有 staticMethod 
typeof EnhancedComponent.staticMethod === 'undefined' // true   
// 記得拷貝staticMethod
 Enhance.staticMethod = WrappedComponent.staticMethod;

由于返回的是一個新的組件,包裹組件的靜態(tài)方法不會被繼承,必須要手動拷貝.

Refs 不會被傳遞

高階組件約定會報所有的props都傳給包裹組件,但是ref不會,ref實際上不是prop-就像 key 一樣益老,它是由 React 專門處理的

高階組件每次都返回一個新的組件,只能在組件聲明式包裹,不利于diff和動態(tài)傳參,render-props完美的解決了這個問題,直接將一個組件作為props傳遞進去

這兩種方式在react樹很大的時候,都會產(chǎn)生回調地獄,所以衍生了 reacthooks

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市寸莫,隨后出現(xiàn)的幾起案子捺萌,更是在濱河造成了極大的恐慌,老刑警劉巖膘茎,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桃纯,死亡現(xiàn)場離奇詭異酷誓,居然都是意外死亡,警方通過查閱死者的電腦和手機态坦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門盐数,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伞梯,你說我怎么就攤上這事玫氢。” “怎么了谜诫?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵漾峡,是天一觀的道長。 經(jīng)常有香客問我喻旷,道長生逸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任且预,我火速辦了婚禮槽袄,結果婚禮上,老公的妹妹穿的比我還像新娘辣之。我一直安慰自己掰伸,他們只是感情好,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布怀估。 她就那樣靜靜地躺著,像睡著了一般合搅。 火紅的嫁衣襯著肌膚如雪多搀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天灾部,我揣著相機與錄音康铭,去河邊找鬼。 笑死赌髓,一個胖子當著我的面吹牛从藤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锁蠕,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼夷野,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了荣倾?” 一聲冷哼從身側響起悯搔,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舌仍,沒想到半個月后妒貌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體通危,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年灌曙,在試婚紗的時候發(fā)現(xiàn)自己被綠了菊碟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡在刺,死狀恐怖框沟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情增炭,我是刑警寧澤忍燥,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站隙姿,受9級特大地震影響梅垄,放射性物質發(fā)生泄漏。R本人自食惡果不足惜输玷,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一队丝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧欲鹏,春花似錦机久、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尤误,卻和暖如春侠畔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背损晤。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工软棺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尤勋。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓喘落,卻偏偏與公主長得像,于是被迫代替她去往敵國和親最冰。 傳聞我的和親對象是個殘疾皇子瘦棋,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

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