高階函數(shù)
高階組件(屬性代理)
- 普通組件還可以向高階組件傳值
- 使用情景:
- 幾個(gè)頁面的布局排版非常相似(只是某一、多個(gè)地方根據(jù)自身類而展示的不同),可以使用高階組件進(jìn)行都一致的布局,A/B/C...等類傳入各自不同的類作為子類。(另外的做法就是組件全部分割為單獨(dú)的類,A/B/C...等進(jìn)行多個(gè)小類的組合成為一個(gè)完整的類)
- 高階組件作為基類存在
高階組件(反向繼承)
普通組件的 static 方法怎么傳入高階組件內(nèi)部
- 使用情景:
- 攔截組件的生命周期函數(shù)及修改state
作用:
- 更改Props(高階組件(屬性代理))
在返回的新組件上傳入新的props- 組合組件(高階組件(屬性代理))
在返回的新組件上可以包裹其他組件,進(jìn)行多個(gè)組件的組合- 修改state(高階組件(反向繼承))
繼承于父類,可以修改父類的state- 渲染劫持(高階組件(反向繼承))
繼承于父類,在渲染父類之前,可以先走子類的邏輯
先說下高階函數(shù)~
高價(jià)函數(shù):一個(gè)函數(shù)就可以接收另一個(gè)函數(shù)作為參數(shù),這種函數(shù)就稱之為高階函數(shù)
-
先寫下普通的函數(shù)
數(shù)據(jù)
this.data = {
name: '張三',
age: '20',
sex: '男',
address: '北京通州區(qū)',
company: '北京朝陽區(qū)'
}
A、B 兩個(gè)頁面都要對同一個(gè)數(shù)據(jù)進(jìn)行操作,不同的是輸出不一樣。
這樣寫的話兩個(gè)頁面會存在同樣的代碼,把 info 當(dāng)做更加復(fù)雜的數(shù)據(jù)處理,代碼冗余會特別多。假如現(xiàn)在又加了一個(gè)C頁面,同樣的數(shù)據(jù)不同的操作......
A頁面
welcome(){
let info = "姓名:" + this.data.name + "\n" +
"年齡:" + this.data.age + "\n" +
"性別:" + this.data.sex + "\n" +
"住址:" + this.data.address + "\n" +
"公司:" + this.data.company
console.log('welcome:\n',info)
}
B頁面
goodBye(){
let info = "姓名:" + this.data.name + "\n" +
"年齡:" + this.data.age + "\n" +
"性別:" + this.data.sex + "\n" +
"住址:" + this.data.address + "\n" +
"公司:" + this.data.company
console.log('goodBye:\n',info)
}
A頁面
this.welcome()
B頁面
this.goodBye()

高階函數(shù)登場~ 蹬蹬蹬蹬蹬蹬蹬蹬~ 丟丟丟~
接受一個(gè)函數(shù)作為參數(shù),返回一個(gè)新的函數(shù)
welcome(info){
console.log('welcome:\n',info)
}
goodBye(info){
console.log('goodBye:\n',info)
}
// 高階函數(shù) 傳入函數(shù),返回函數(shù)
hocFunc(func){
let newFunc = ()=>{
let info = "姓名:" + this.data.name + "\n" +
"年齡:" + this.data.age + "\n" +
"性別:" + this.data.sex + "\n" +
"住址:" + this.data.address + "\n" +
"公司:" + this.data.company
func(info)
}
return newFunc
}
let hocWelcome= this.hocFunc(this.welcome)
hocWelcome()
let hocGoodbye = this.hocFunc(this.goodBye)
hocGoodbye()
假如現(xiàn)在增加C頁面,就可以這樣寫
sleep(info){
console.log('sleep:\n',info)
}
let hocSleep = this.hocFunc(this.sleep)
hocSleep()
高階組件
通過類比,大概可以知道高階組件是怎么回事嘍~
a higher-order component is a function that takes a component and returns a new component.
高階組件就是一個(gè)函數(shù),且該函數(shù)接受一個(gè)組件作為參數(shù),并返回一個(gè)新的組件。
將 welcome goodBye 當(dāng)做普通的組件
import React, {PureComponent, Component} from 'react';
import {
View,
StyleSheet,
Text
} from "react-native"
export default class welcome extends PureComponent {
constructor(props, context){
super(props)
this.state = {
info: ''
}
this.data = {
name: '張三',
age: '20',
sex: '男',
address: '北京通州區(qū)',
company: '北京朝陽區(qū)'
}
}
componentDidMount() {
let info = "姓名:" + this.data.name + "\n" +
"年齡:" + this.data.age + "\n" +
"性別:" + this.data.sex + "\n" +
"住址:" + this.data.address + "\n" +
"公司:" + this.data.company
this.setState({
info
})
}
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>welcome:{this.state.info}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
view: {
justifyContent: 'center',
alignItems: 'center',
height: 200,
backgroundColor: 'red'
},
text: {
color: 'white',
marginBottom: 30
}
})
import React, {PureComponent, Component} from 'react';
import {
View,
StyleSheet,
Text
} from "react-native"
export default class goodbye extends PureComponent {
constructor(props, context){
super(props)
this.state = {
info: ''
}
this.data = {
name: '張三',
age: '20',
sex: '男',
address: '北京通州區(qū)',
company: '北京朝陽區(qū)'
}
}
componentDidMount() {
let info = "姓名:" + this.data.name + "\n" +
"年齡:" + this.data.age + "\n" +
"性別:" + this.data.sex + "\n" +
"住址:" + this.data.address + "\n" +
"公司:" + this.data.company
this.setState({
info
})
}
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>goodBye:{this.state.info}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
view: {
justifyContent: 'center',
alignItems: 'center',
height: 200,
backgroundColor: 'blue'
},
text: {
color: 'white',
marginBottom: 30
}
})

設(shè)計(jì)高階組件(方式一:屬性代理)
屬性代理:組件的數(shù)據(jù)流動都由普通組件流通到高階組件內(nèi)部,通過高階組件再傳遞給新的組件。高階組件可以對數(shù)據(jù)提前進(jìn)行增刪改查等操作,也可以對組件的布局重定義
高階組件就是一個(gè)函數(shù),且該函數(shù)接受一個(gè)組件作為參數(shù),并返回一個(gè)新的組件。
最簡單的高階組件
import React, {Component} from 'react'
// 獲取組件的名字
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
export default (WrappedComponent) => {
class NewComponent extends Component {
render() {
return <WrappedComponent {...this.props}/>
}
}
NewComponent.displayName = `HOC(${getDisplayName(WrappedComponent)})`;
return NewComponent
}
優(yōu)化一下下......
welcome
import React, {PureComponent, Component} from 'react';
import {
View,
StyleSheet,
Text
} from "react-native"
import HocComponent from './hocComponent'
// 方法一:
// ES7 語法,裝飾器 export default welcome
@HocComponent
class welcome extends PureComponent {
constructor(props, context){
super(props)
}
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>welcome:{this.props.info}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
view: {
justifyContent: 'center',
alignItems: 'center',
height: 200,
backgroundColor: 'red'
},
text: {
color: 'white',
marginBottom: 30
}
})
export default welcome
// 方法二:
// export default HocComponent(welcome)
goodbye
import React, {PureComponent, Component} from 'react';
import {
View,
StyleSheet,
Text
} from "react-native"
import HocComponent from './hocComponent'
// 方法一:
// ES7 語法,裝飾器 export default welcome
@HocComponent
class goodbye extends PureComponent {
constructor(props, context){
super(props)
}
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>goodBye:{this.props.info}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
view: {
justifyContent: 'center',
alignItems: 'center',
height: 200,
backgroundColor: 'blue'
},
text: {
color: 'white',
marginBottom: 30
}
})
export default goodbye
// 方法二:
// export default HocComponent(goodbye)
hocComponent 高階組件
import React, {Component} from 'react'
import {
View,
Text
} from 'react-native'
export default (WrappedComponent) => {
// WrappedComponent 傳進(jìn)來的組件
class NewComponent extends Component {
// 在 返回新的組件之前,對數(shù)據(jù)進(jìn)行處理
constructor(props){
super(props)
this.state = {
info: ''
}
this.data = {
name: '張三',
age: '20',
sex: '男',
address: '北京通州區(qū)',
company: '北京朝陽區(qū)'
}
this.newProps = {
phone: '151......',
email: '111@...',
qq: '123...',
wx: 'qwer...'
}
}
componentDidMount() {
let info = "姓名:" + this.data.name + "\n" +
"年齡:" + this.data.age + "\n" +
"性別:" + this.data.sex + "\n" +
"住址:" + this.data.address + "\n" +
"公司:" + this.data.company
this.setState({
info
})
}
// {...this.props} 確保原來的組件的 props 不變
// info={this.state.info} 對新的組件進(jìn)行新的賦值
// {...this.newProps} 對新的組件進(jìn)行新的傳參
// <View>......</View> 對新的組件進(jìn)行擴(kuò)展,加入新的組件
render() {
return <View style={{marginTop: 40, justifyContent: 'center', alignItems: 'center', backgroundColor: 'purple'}}>
<Text style={{color: 'white'}}>通過 高階組件 進(jìn)行處理后的組件</Text>
<WrappedComponent {...this.props} info={this.state.info} {...this.newProps}/>
</View>
}
}
return NewComponent
}
普通組件還可以向高階組件傳值
import React, {Component} from 'react'
import {
View,
Text
} from 'react-native'
export default (WrappedComponent) => (options) => {
// WrappedComponent 傳進(jìn)來的組件
// options 普通組件傳進(jìn)來的參數(shù)
class NewComponent extends Component {
// 在 返回新的組件之前,對數(shù)據(jù)進(jìn)行處理
constructor(props){
super(props)
this.state = {
info: ''
}
this.data = {
name: '張三',
age: '20',
sex: '男',
address: '北京通州區(qū)',
company: '北京朝陽區(qū)'
}
this.newProps = {
phone: '151......',
email: '111@...',
qq: '123...',
wx: 'qwer...'
}
}
componentDidMount() {
let info = "姓名:" + this.data.name + "\n" +
"年齡:" + this.data.age + "\n" +
"性別:" + this.data.sex + "\n" +
"住址:" + this.data.address + "\n" +
"公司:" + this.data.company
this.setState({
info
})
}
// {...this.props} 確保原來的組件的 props 不變
// info={this.state.info} 對新的組件進(jìn)行新的賦值
// {...this.newProps} 對新的組件進(jìn)行新的傳參
// <View>......</View> 對新的組件進(jìn)行擴(kuò)展,加入新的組件
render() {
return <View style={{marginTop: 40, justifyContent: 'center', alignItems: 'center', backgroundColor: 'purple'}}>
<Text style={{color: 'white'}}>通過 高階組件 進(jìn)行處理后的組件:{options.title}</Text>
<WrappedComponent {...this.props} info={this.state.info} {...this.newProps}/>
</View>
}
}
return NewComponent
}
ES7語法 裝飾器 使用方法
@HocComponent
class welcome extends PureComponent {
}
export default welcome({title: 'A'})
普通的使用方法
export default HocComponent(goodbye)({title: 'B'})
設(shè)計(jì)高階組件(方式二:反向繼承)
高階組件繼承于普通組件,即 高階組件可以獲取、重寫普通組件里面的函數(shù),包括生命周期函數(shù);可以修改普通組件內(nèi)部state數(shù)據(jù)
import React, {PureComponent, Component} from 'react';
import {
View,
StyleSheet,
Text
} from "react-native"
import HocComponent from './hoc1Component'
// 方法一:
// ES7 語法,裝飾器 export default sleep
@HocComponent
class sleep extends PureComponent {
constructor(props, context){
super(props)
this.state = {
result: '組件'
};
this.actionClick = this.actionClick.bind(this)
}
componentDidMount() {
console.log('2')
}
actionClick(){
return "這是一個(gè) "
}
render() {
console.log('render')
return (
<View style={styles.view}>
<Text style={styles.text}>sleep:{this.state.result}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
view: {
justifyContent: 'center',
alignItems: 'center',
height: 200,
backgroundColor: 'green'
},
text: {
color: 'white',
marginBottom: 30
}
});
export default sleep
// 方法二:
// export default HocComponent(sleep)
高階組件(反向繼承)
import React, {Component} from 'react'
export default (WrappedComponent) => {
// 繼承 于 WrappedComponent
class NewComponent extends WrappedComponent {
componentDidMount() {
// 此處 重寫了父類的方法,父類就不會再執(zhí)行 componentDidMount()
console.log('1')
// 修改父類的 state
this.setState({
result: '通過高階組件(反向繼承方式)創(chuàng)建的組件'
})
}
// 重寫 父類 的方法
actionClick(){
return "abc"
}
render(){
return super.render()
}
}
return NewComponent
}
不想把整個(gè)組件當(dāng)成高階組件時(shí),比如組件內(nèi)部的某些組件需要高階組件來裝飾,可以這樣寫
function CustomButton() {
return <button ...... />;
}
const MyButton = withTitle(Button);
CustomButton是自定義的組件,withTitle是一個(gè)高階組件(比如可以添加防重復(fù)點(diǎn)擊),MyButton是在render()里面要使用的組件
普通組件的 static 方法怎么傳入高階組件內(nèi)部
當(dāng)使用高階組件包裝組件,原始組件被容器組件包裹,也就意味著新組件會丟失原始組件的所有靜態(tài)方法
解決這個(gè)問題的方法就是,將原始組件的所有靜態(tài)方法全部拷貝給新組件:
普通組件內(nèi)部定義了 static 方法
static ABC(){
return 'abc'
}
高階組件內(nèi)部
NewComponent.ABC = WrappedComponent.ABC
注意事項(xiàng)
不要在render函數(shù)中使用高階組件
- 每一次render函數(shù)調(diào)用都會創(chuàng)建一個(gè)新的高階組件實(shí)例 ,引起性能問題
- 會引起原有組件的所有狀態(tài)和子組件丟失
必須將靜態(tài)方法做拷貝
- 當(dāng)使用高階組件包裝組件,原始組件被容器組件包裹,也就意味著新組件會丟失原始組件的所有靜態(tài)方法。
Refs屬性不能傳遞
更加詳細(xì)的文檔參考RN中文網(wǎng) https://react.docschina.org/docs/higher-order-components.html