React高阶组件应用

本文主要记录如何使用高阶组件实现外部逻辑注入,如性能打点,以及其中遇到的一些问题

The defination of HOC

所谓高级组件,即:接受一个组件作为参数,并且其返回值也为一个react组件

demo

如下是一个再简单不过的react组件

import connect from './connect'
import {Component}  from 'react'

class Demo extends Component {
    componentWillMount(){
        //do something here
    }
    render(){
        return <div>111</div>
    }
}
export default connect(Demo)

connect 是一个实现性能打点的装饰器,here is the source code

装饰器,在本质上,其实是返回一个函数的高阶函数。在react应用中,衍生出了高阶组件的含义

以下是两种HOC的实现方式:

方式一:Props Proxy

//性能追踪:渲染时间打点
export default (Target) => (props)=>{
    let func1 = Target.prototype['componentWillMount']    
    let func2 = Target.prototype['componentDidMount']//Demo并没有在prototype上定义该方法,func2为undefined,但是并不会有影响,这样做只是为了事先提取出可能定义的逻辑,保持原函数的纯净
    let begin, end;
    Target.prototype['componentWillMount'] = function (...argus){//do not use arrow funciton to bind 'this' object
        func1.apply(this,argus);//执行原有的逻辑
        begin = Date.now();
    }
    Target.prototype['componentDidMount'] = function (...argus){
        func2.apply(this,argus);//执行原有的逻辑
        end = Date.now();
        console.log(Target.name+'组件渲染时间:'+(end-begin)+'毫秒')
    }
    return <Target {...props}/>//do not forget to pass props to the element of Target
}

connect 装饰器可以实现保持原有方法componentWillMountcomponentDidMount纯净的情况下,实现打点逻辑的无污染注入。经过装饰以后的组件,就可以在控制台打印出该组件的渲染时间。

方式二: Inheritance Inversion

// 另一种HOC的实现方式 Inheritance Inversion

export default Target => class Enhancer extends Target {
    constructor(p){
        super(p);//es6 继承父类的this对象,并对其修改,所以this上的属性也被继承过来,可以访问,如state
        this.end =0;
        this.begin=0;
    }
    componentWillMount(){
        super.componentWilMount && super.componentWilMount();// 如果父类没有定义该方法,直接调用会出错
        this.begin = Date.now();
    }
    componentDidMount(){
        super.componentDidMount && super.componentDidMount();
        this.end=Date.now();
        console.log(Target.name+'组件渲染时间'+(this.end-this.begin)+'ms')
    }
    render(){
        let ele = super.render();//调用父类的render方法
        return ele;//可以在这之前完成渲染劫持
    }
}

你可以看到,返回的 HOC 类(Enhancer)继承了 Target。之所以被称为 Inheritance Inversion 是因为 TargetEnhancer继承了,而不是Target继承了Enhancer。在这种方式中,它们的关系看上去被反转(inverse)了。

Inheritance Inversion 允许 HOC 通过this 访问到 Target,意味着它可以访问到 stateprops组件生命周期方法render方法。

遗留问题

如何去手动connect,对项目中定义的所有react组件实现自动逻辑注入(talentLibs库的实现方式是什么样的?)

Other Questions

这里主要记录在写demo的过程中,遇到的几个问题:

关于箭头函数

在给类定义方法时,如果使用了箭头函数,发现在prototype上访问不到该方法,主要原因如下:
what happens when using arrow function to define method on class

//deom1
class Super{
    sayName(){
        //do some thing here
    }
}
//通过Super.prototype可以访问到sayName方法,这种形式定义的方法,都是定义在prototype上
var a = new Super()
var b = new Super()
a.sayName === b.sayName //true
//所有实例化之后的对象共享prototypy上的sayName方法


//demo2
class Super{
    sayName =()=>{
        //do some thing here
    }
}
//通过Super.prototype访问不到sayName方法,该方法没有定义在prototype上
var a = new Super()
var b = new Super()
a.sayName === b.sayName //false
//实例化之后的对象各自拥有自己的sayName方法,比demo1需要更多的内存空间

通过demo1这种方式,我们可以在Super.prototype上访问到sayName方法

但是通过使用demo2的定义方式,我们在Super.prototype上访问不到sayName方法

Conclusion

if you use the reserved key word class in ES6 to declare a class like demo1,the method will be defined on the prototype.However,when using arrow function,the method will be bound with this.

在定义一个类时,如果使用demo1中的方式给类添加方法,那么这个方法将被定义在类的prototype上。然而如果使用箭头函数的话,这个方法将会被定义在this上,即Super的实例化之后的对象。而且在这个方法内,this始终会指向这个对象,而不管方法的调用方式(箭头函数的特性)

Reference

深入了解HOC

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值