React-Native 高阶组件

高阶函数

高阶组件(属性代理)

  • 普通组件还可以向高阶组件传值
  • 使用情景:
  1. 几个页面的布局排版非常相似(只是某一、多个地方根据自身类而展示的不同),可以使用高阶组件进行都一致的布局,A/B/C...等类传入各自不同的类作为子类。(另外的做法就是组件全部分割为单独的类,A/B/C...等进行多个小类的组合成为一个完整的类)
  2. 高阶组件作为基类存在

高阶组件(反向继承)

普通组件的 static 方法怎么传入高阶组件内部

  • 使用情景:
  1. 拦截组件的生命周期函数及修改state

作用:

  • 更改Props(高阶组件(属性代理))
    在返回的新组件上传入新的props
  • 组合组件(高阶组件(属性代理))
    在返回的新组件上可以包裹其他组件,进行多个组件的组合
  • 修改state(高阶组件(反向继承))
    继承于父类,可以修改父类的state
  • 渲染劫持(高阶组件(反向继承))
    继承于父类,在渲染父类之前,可以先走子类的逻辑

先说下高阶函数~

高价函数:一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

  • 先写下普通的函数

数据
this.data = {
            name: '张三',
            age: '20',
            sex: '男',
            address: '北京通州区',
            company: '北京朝阳区'
        }

A、B 两个页面都要对同一个数据进行操作,不同的是输出不一样。
这样写的话两个页面会存在同样的代码,把 info 当做更加复杂的数据处理,代码冗余会特别多。假如现在又加了一个C页面,同样的数据不同的操作......

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

高阶函数登场~ 蹬蹬蹬蹬蹬蹬蹬蹬~ 丢丢丢~

接受一个函数作为参数,返回一个新的函数

    welcome(info){
        console.log('welcome:\n',info)
    }

    goodBye(info){
        console.log('goodBye:\n',info)
    }

    // 高阶函数 传入函数,返回函数
    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()
假如现在增加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.
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
将 welcome goodBye 当做普通的组件

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: '北京通州区',
            company: '北京朝阳区'
        }

    }

    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: '北京通州区',
            company: '北京朝阳区'
        }

    }

    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

设计高阶组件(方式一:属性代理)

属性代理:组件的数据流动都由普通组件流通到高阶组件内部,通过高阶组件再传递给新的组件。高阶组件可以对数据提前进行增删改查等操作,也可以对组件的布局重定义

高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。

最简单的高阶组件

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
}

优化一下下......

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 传进来的组件

    class NewComponent extends Component {

        // 在 返回新的组件之前,对数据进行处理

        constructor(props){
            super(props)
            this.state = {
                info: ''
            }
            this.data = {
                name: '张三',
                age: '20',
                sex: '男',
                address: '北京通州区',
                company: '北京朝阳区'
            }

            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}  对新的组件进行新的赋值

        // {...this.newProps} 对新的组件进行新的传参

        // <View>......</View> 对新的组件进行扩展,加入新的组件

        render() {
            return <View style={{marginTop: 40, justifyContent: 'center', alignItems: 'center', backgroundColor: 'purple'}}>
                <Text style={{color: 'white'}}>通过 高阶组件 进行处理后的组件</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 传进来的组件

    // options 普通组件传进来的参数

    class NewComponent extends Component {

        // 在 返回新的组件之前,对数据进行处理

        constructor(props){
            super(props)
            this.state = {
                info: ''
            }
            this.data = {
                name: '张三',
                age: '20',
                sex: '男',
                address: '北京通州区',
                company: '北京朝阳区'
            }

            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}  对新的组件进行新的赋值

        // {...this.newProps} 对新的组件进行新的传参

        // <View>......</View> 对新的组件进行扩展,加入新的组件

        render() {
            return <View style={{marginTop: 40, justifyContent: 'center', alignItems: 'center', backgroundColor: 'purple'}}>
                <Text style={{color: 'white'}}>通过 高阶组件 进行处理后的组件:{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'})

设计高阶组件(方式二:反向继承)

高阶组件继承于普通组件,即 高阶组件可以获取、重写普通组件里面的函数,包括生命周期函数;可以修改普通组件内部state数据

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 "这是一个 "
    }

    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() {
            // 此处 重写了父类的方法,父类就不会再执行 componentDidMount()
            console.log('1')

            // 修改父类的 state
            this.setState({
                result: '通过高阶组件(反向继承方式)创建的组件'
            })
        }

        // 重写 父类 的方法
        actionClick(){
            return "abc"
        }

        render(){
           return super.render()
        }
    }

    return NewComponent
}

不想把整个组件当成高阶组件时,比如组件内部的某些组件需要高阶组件来装饰,可以这样写

function CustomButton() {
  return <button ...... />;
}

const MyButton = withTitle(Button);

CustomButton 是自定义的组件,withTitle是一个高阶组件(比如可以添加防重复点击), MyButton是在render()里面要使用的组件

普通组件的 static 方法怎么传入高阶组件内部

当使用高阶组件包装组件,原始组件被容器组件包裹,也就意味着新组件会丢失原始组件的所有静态方法
解决这个问题的方法就是,将原始组件的所有静态方法全部拷贝给新组件:
普通组件内部定义了 static 方法

 static ABC(){
        return 'abc'
    }

高阶组件内部

NewComponent.ABC = WrappedComponent.ABC

注意事项

不要在render函数中使用高阶组件

  • 每一次render函数调用都会创建一个新的高阶组件实例 ,引起性能问题
  • 会引起原有组件的所有状态和子组件丢失

必须将静态方法做拷贝

  • 当使用高阶组件包装组件,原始组件被容器组件包裹,也就意味着新组件会丢失原始组件的所有静态方法。

Refs属性不能传递

更加详细的文档参考RN中文网 https://react.docschina.org/docs/higher-order-components.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,273评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,349评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,709评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,520评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,515评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,158评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,755评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,660评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,203评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,287评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,427评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,122评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,801评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,272评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,393评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,808评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,440评论 2 359

推荐阅读更多精彩内容

  • React进阶之高阶组件 前言 本文代码浅显易懂,思想深入实用。此属于react进阶用法,如果你还不了解react...
    流动码文阅读 1,186评论 0 1
  • 前言 学习react已经有一段时间了,期间在阅读官方文档的基础上也看了不少文章,但感觉对很多东西的理解还是不够深刻...
    Srtian阅读 1,661评论 0 7
  • 看题目感觉好高级的样子,千万不要被名字吓到,它一点都不高深。按照惯例先上图,这一章的概览: 1.从高阶函数说起 维...
    酸菜鱼黄焖鸡阅读 740评论 0 1
  • In this article we will discuss how to use Higher Order C...
    人头原子弹阅读 573评论 0 0
  • 今天下午大家一起做纸飞机。小芮坐在垫子上耐心的看,折好第一架飞机的时候,小芮很想要,当飞机飞到他跟前时,小芮开心的...
    ic班阅读 186评论 0 0