ReactNative中的高階組件(HOC)和繼承詳解
共同點:
- 高階組件(HOC)是 React 中用于復(fù)用組件邏輯的一種高級技巧册烈。HOC 自身不是 React API 的一部分删性,它是一種基于 React 的組合特性而形成的設(shè)計模式。
- 繼承也是用于解決復(fù)用代碼的一種技巧
不同點:
- 高階組件是參數(shù)為組件钓辆,返回值為新組件的函數(shù)
- 繼承是類繼承類坤按,是面向?qū)ο蟮囊淮筇攸c
本文以FlatList為例惊豺,詳解高階組件和繼承的使用!為啥是FlatList尼坚俗?
因為FlatList使用廣泛镜盯,造成大量重復(fù)代碼,僅僅是因為樣式不同而導(dǎo)致猖败,使用高階組件速缆,可以傳入被包裹的樣式組件,由高階組件統(tǒng)一實現(xiàn)FlatList的方法恩闻,由此可以減少重復(fù)代碼艺糜,減少耦合,其他場景等同
高階組件(HOC)
高階組件的樣式:
function HOC(WrappedComponent) {
return class Component extends React.Component {
render() {
// 將WrappedComponent組件包裝在容器中幢尚,而不對其進行修改破停。Good!
return <WrappedComponent {...this.props} />;
}
}
而我們要改變的不是傳入的FlatList,而是renderItem組件尉剩,首先在高階組件中實現(xiàn)FlatList:
keyExtractor = (item, index) => {
return index.toString()
}
listHeaderComponent = () => {
return (
<View style={{marginTop: Dimens.dx_60}}/>
)
}
listFooterComponent = () => {
if (this.state.showFoot) {
return (
<View style={styles.footView}>
<Text style={styles.footText}>
沒有更多數(shù)據(jù)了
</Text>
</View>
)
} else {
return (
<View style={styles.footLoadingView}>
<Text style={styles.footLoadingText}>
正在加載中...
</Text>
</View>
)
}
}
onEndReached = () => {
if (this.hasNextPage === 1) {
this.pageIndex++,
this.setState({
showFoot: false
})
this.getNetworkingDataFunction(this.pageIndex, 20)
} else {
this.setState({
showFoot: true
})
}
}
flatListRenderItem = (item) => {
return (
<WrappedComponent {...this.props} {...item} />
)
}
onRetry = () => {
this.getNetworkingDataFunction(this.pageIndex, 20)
}
render() {
if (this.state.error) {
return (
<LoadFailView onRetry={this.onRetry}/>
)
}
if (this.state.list && this.state.list.length) {
return (
<View style={{backgroundColor: Colors.bgColor, flex: 1}}>
<FlatList
keyExtractor={this.keyExtractor.bind(this)}
horizontal={false}
data={this.state.list}
numColumns={WrappedComponent.numOfColumn()}
showsVerticalScrollIndicator={false}
renderItem={this.flatListRenderItem.bind(this)}
ListHeaderComponent={this.listHeaderComponent.bind(this)}
ListFooterComponent={this.listFooterComponent.bind(this)}
onEndReached={this.onEndReached.bind(this)}
onEndReachedThreshold={0.01}
/>
</View>
)
} else {
return <EmptyView text={this.state.empty}/>
}
}
}
毫無疑問在以上代碼中你已經(jīng)看到flatListRenderItem返回的組件才是被包裹組件真慢,現(xiàn)在只需要解決數(shù)據(jù)問題,高階組件FlatList就完成了
由于高階組件中獲取不了被包裹組件的實例理茎,需要在被包裹組件中聲明靜態(tài)網(wǎng)絡(luò)請求方法:getNetworkingFunction
/**
* Takes network data from server
* 無默認(rèn)配置黑界,組件中有網(wǎng)絡(luò)請求需實現(xiàn)異步Promise:
**/
getNetworkingDataFunction = (pageIndex, pageSize) => {
WrappedComponent.getNetworkingFunction(pageIndex, pageSize).then(results => {
}).catch(error => {
})
}
在被包裹組件中:
此處需要用到異步Promise
static getNetworkingFunction = (pageIndex,pageSize)=> {
return new Promise(function (resolve, reject) {
requestGetIntegralExchangeRecordList(pageIndex, pageSize).then(results => {
resolve(results)
}).catch(error => {
reject(error)
})
})
}
用來控制FlatList的column
static numOfColumn = () =>{
return 1;
}
傳入各樣式的item組件即可
render() {
}
繼承
父類:
export default class BaseComponent extends React.Component {
}
子類:
export default class childComponent extends BaseComponent {
}
父類中實現(xiàn)FlatList
/**
* Takes network data from server
* 無默認(rèn)配置,必須繼承實現(xiàn)
**/
getNetworkingDataFunction = () =>{
}
/**
* Takes an item from data and renders it into the list. Typical usage:
* 無默認(rèn)配置皂林,必須繼承實現(xiàn)
*/
flatListRenderItem = (item) =>{
}
/**
* Rendered at the very beginning of the list.
* 默認(rèn)配置如下朗鸠,可通過繼承實現(xiàn)修改
*/
listHeaderComponent = () => {
return (
<View style={{marginTop: Dimens.dx_60}}/>
)
}
/**
* Rendered at the very end of the list.
* 默認(rèn)配置如下,可通過繼承實現(xiàn)修改
*/
listFooterComponent = () => {
if (this.state.showFoot) {
return (
<View style={styles.footView}>
<Text style={styles.footText}>
沒有更多數(shù)據(jù)了
</Text>
</View>
)
} else {
return (
<View style={styles.footLoadingView}>
<Text style={styles.footLoadingText}>
正在加載中...
</Text>
</View>
)
}
}
keyExtractor = (item, index) => {
return index.toString()
}
onEndReached = () =>{
if (this.hasNextPage === 1) {
this.pageIndex++,
this.setState({
showFoot: false
})
this.getNetworkingDataFunction(this.pageIndex,20)
} else {
this.setState({
showFoot: true
})
}
}
render(){
if (this.state.list && this.state.list.length){
return (
<View style={{backgroundColor: Colors.bgColor, flex: 1}}>
<FlatList
keyExtractor={this.keyExtractor.bind(this)}
horizontal={false}
data={this.state.list}
showsVerticalScrollIndicator={false}
renderItem={this.flatListRenderItem.bind(this)}
ListHeaderComponent={this.listHeaderComponent.bind(this)}
ListFooterComponent={this.listFooterComponent.bind(this)}
onEndReached={this.onEndReached.bind(this)}
onEndReachedThreshold={0.01}
/>
</View>
)
}else {
return <EmptyView text={this.state.emptyText}/>
}
}
在子類中去重寫父類的方法
* 網(wǎng)絡(luò)請求方法:getNetworkingDataFunction
* render內(nèi)容展示:flatListRenderItem
getNetworkingDataFunction = (pageIndex,pageSize) => {
requestGetIntegralExchangeRecordList(pageIndex, pageSize).then(results => {
}).catch(error => {
})
}
flatListRenderItem = ({item}) =>{
return (
<TouchableOpacity onPress={event => {
this.onClick(item)
}}>
<RenderItem item={item} />
</TouchableOpacity>
)
}
onClick(item) {
}
class RenderItem extends React.Component{
}
那為什么react-native不推薦使用繼承础倍?
react中推薦使用組合和高階組件來替代繼承童社,網(wǎng)上關(guān)于react的繼承也是微乎其微,對于iOS出身的我來說著隆,繼承主要有一下缺點:
- 父類的內(nèi)部細(xì)節(jié)對子類是可見的
- 如果父類做了修改扰楼,所有涉及的子類必須修改呀癣,高耦合。
- 繼承也有可能使程序變得難以閱讀弦赖。調(diào)用一個方法時,有時很難判斷它是在哪定義的项栏,子類中查找問題必須去父類中查看