1. 概念
很多情況下冰木,需要給多個(gè)組件添加或者修改一些特定的props柬甥,或者在所有組件基礎(chǔ)上加個(gè)水印等等灶轰。而如果這個(gè)功能如果是針對(duì)多個(gè)組件的噪奄,每一個(gè)組件都寫(xiě)一套相同的代碼死姚,顯得不是很明智,所以就可以考慮使用高階組件勤篮。
ReactNative的高階組件也叫HOC(全稱Higher-order component)都毒,構(gòu)建方式主要有屬性代理
和反向繼承
。主要用于:
- 組件代碼復(fù)用碰缔,代碼模塊化
- 增刪改props
- 渲染劫持
- ……
所以高階組件經(jīng)常作為一個(gè)函數(shù)账劲,且該函數(shù)接受一個(gè)組件作為參數(shù),并返回一個(gè)新的組件。
2. 使用
2.1 組件代碼復(fù)用涤垫,代碼模塊化
下面是一個(gè)簡(jiǎn)單的高階組件姑尺,給傳進(jìn)去的組件前面加了一個(gè)固定的Text組件。
# 定義
export const HocComponent = (param) => (WrappedComponent) => {
class NewComponent extends React.Component {
render() {
return(
<View>
<Text>我是高階組件,傳進(jìn)來(lái)參數(shù)是:{JSON.stringify(param)}</Text>
<WrappedComponent {...this.props}/>
</View>
)
}
}
return NewComponent
}
HocComponent 是一個(gè)函數(shù)蝠猬,param是需要傳入組件的參數(shù)切蟋,WrappedComponent是傳入的組件,NewComponent就是傳入?yún)?shù)后生成的新的組件榆芦。
使用方式推薦用裝飾器語(yǔ)法柄粹, 如下圖就可以給TestComp和TestComp2組件傳入?yún)?shù)都加上一個(gè)Text組件。
# 裝飾器調(diào)用
@HocComponent({name:'zhangsan'})
export class TestComp extends React.Component<IProps> {
...
}
# 裝飾器調(diào)用
@HocComponent({name:'lisi'})
export class TestComp2 extends React.Component<IProps> {
...
}
# 函數(shù)調(diào)用 ( HocComponent改成返回<NewComponent/>)
const TestComp = HocComponent({name:'zhangsan'})(TestComp )
2.2 增刪改Props
也可以在基礎(chǔ)上加入特定props匆绣,例如在高階組件內(nèi)部自定義一個(gè)顏色主題themeType,這樣就可以在新返回的組件通過(guò)this.props.themeType獲取當(dāng)前的顏色主題驻右。
export default (Comp)=>{
class newCom extends React.Component{
const newProps = {
...this.props,
themeType:'dark'
}
render() {
return <Comp {...newProps}/>
}
}
return newCom
}
2.3 渲染劫持
在render方法里控制顯示渲染邏輯,下面是一個(gè)例子崎淳。
當(dāng)屬性this.props.loading為true時(shí)顯示加載組件堪夭,當(dāng)屬性this.props.data數(shù)據(jù)為空時(shí)顯示空白組件,正常則直接顯示渲染傳入的<Comp/>組件拣凹。
const HocComponent = (WrappedComponent)=>{
newComp extends WrappedComponent {
render(){
if(this.props.loading){
return <View><Text>加載中</Text></View>
}
if(this.props.data.length>0){
return <View><Text>暫無(wú)數(shù)據(jù)</Text></View>
}
return super.render();
}
}
return newComp
}
需要注意的是:
- 普通組件的 static方法怎么傳入高階組件內(nèi)部?
當(dāng)使用高階組件包裝組件森爽,原始組件被容器組件包裹,也就意味著新組件會(huì)丟失原始組件的所有靜態(tài)方法嚣镜。解決這個(gè)問(wèn)題的方法就是爬迟,將原始組件的所有靜態(tài)方法全部拷貝給新組件:
# 普通組件內(nèi)部定義了 static 方法
static ABC(){
return 'abc'
}
# 高階組件內(nèi)部
NewComponent.ABC = WrappedComponent.ABC
3. 屬性代理與反向繼承
對(duì)于函數(shù)內(nèi)部高階組件的生成主要由以下兩種:
- 屬性代理:高階組件通過(guò)
包裹
傳進(jìn)來(lái)React組件進(jìn)行操作; - 反向繼承:高階組件
繼承
于被包裹的React組件進(jìn)行操作菊匿。
上面所說(shuō)的(1)(2)主要是屬性代理的使用方式付呕,(3)反向繼承的案例,下面是反向繼承的詳細(xì)案例跌捆。
const HocComponent = (WrappedComponent)=>{
newComp extends WrappedComponent {
// 此處重寫(xiě)了父類的方法父類就不會(huì)再執(zhí)行 componentDidMount()
componentDidMount() {
console.log('1')
// 修改父類的 state
this.setState({
result: '通過(guò)高階組件(反向繼承方式)創(chuàng)建的組件'
})
}
render(){
return super.render();
}
}
return newComp
}
屬性代理和反向繼承主要的區(qū)別是
- 屬性代理:靈活操作組件的props徽职,如上述的增刪改props,再把props傳給組件。
- 反向繼承:攔截生命周期佩厚、state活箕、渲染過(guò)程。因?yàn)槔^承了傳進(jìn)來(lái)的組件可款,如果新組件寫(xiě)了componentDidMount等方法,會(huì)覆蓋掉原方法;也可以在外部組件調(diào)用被繼承組件的方法克蚂,如super.render();
4. 總結(jié)
這篇文章主要講解了HOC的概念和使用思路闺鲸,需要注意的是,在創(chuàng)建HOC的過(guò)程中盡量不要改變?cè)冀M件埃叭,而是使用組合的方式摸恍。HOC的實(shí)際使用場(chǎng)景要比現(xiàn)在講的還要多,例如頁(yè)面權(quán)限管理、數(shù)據(jù)組裝關(guān)聯(lián)立镶、監(jiān)控日志打印壁袄、埋點(diǎn)上報(bào)等等,靈活運(yùn)用好HOC能夠?qū)N的架構(gòu)邏輯起到很好的幫助與擴(kuò)展媚媒。
參考
React高階組件中文文檔
React Native高階組件(HOC)模型理論與實(shí)踐
React-Native 高階組件