React-Native 高階組件

高階函數(shù)

高階組件(屬性代理)

  • 普通組件還可以向高階組件傳值
  • 使用情景:
  1. 幾個(gè)頁面的布局排版非常相似(只是某一、多個(gè)地方根據(jù)自身類而展示的不同),可以使用高階組件進(jìn)行都一致的布局,A/B/C...等類傳入各自不同的類作為子類。(另外的做法就是組件全部分割為單獨(dú)的類,A/B/C...等進(jìn)行多個(gè)小類的組合成為一個(gè)完整的類)
  2. 高階組件作為基類存在

高階組件(反向繼承)

普通組件的 static 方法怎么傳入高階組件內(nèi)部

  • 使用情景:
  1. 攔截組件的生命周期函數(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()
image.png

高階函數(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
    }
})
image.png

設(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • React進(jìn)階之高階組件 前言 本文代碼淺顯易懂,思想深入實(shí)用。此屬于react進(jìn)階用法,如果你還不了解react...
    流動碼文閱讀 1,238評論 0 1
  • 前言 學(xué)習(xí)react已經(jīng)有一段時(shí)間了,期間在閱讀官方文檔的基礎(chǔ)上也看了不少文章,但感覺對很多東西的理解還是不夠深刻...
    Srtian閱讀 1,761評論 0 7
  • 看題目感覺好高級的樣子,千萬不要被名字嚇到,它一點(diǎn)都不高深。按照慣例先上圖,這一章的概覽: 1.從高階函數(shù)說起 維...
    酸菜魚黃燜雞閱讀 808評論 0 1
  • In this article we will discuss how to use Higher Order C...
    人頭原子彈閱讀 692評論 0 0
  • 今天下午大家一起做紙飛機(jī)。小芮坐在墊子上耐心的看,折好第一架飛機(jī)的時(shí)候,小芮很想要,當(dāng)飛機(jī)飛到他跟前時(shí),小芮開心的...
    ic班閱讀 234評論 0 0

友情鏈接更多精彩內(nèi)容