React高阶组件应用

    xiaoxiao2021-03-25  84

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

    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 装饰器可以实现保持原有方法componentWillMount和componentDidMount纯净的情况下,实现打点逻辑的无污染注入。经过装饰以后的组件,就可以在控制台打印出该组件的渲染时间。

    方式二: 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 是因为 Target被Enhancer继承了,而不是Target继承了Enhancer。在这种方式中,它们的关系看上去被反转(inverse)了。

    Inheritance Inversion 允许 HOC 通过this 访问到 Target,意味着它可以访问到 state、props、组件生命周期方法和 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

    转载请注明原文地址: https://ju.6miu.com/read-25402.html

    最新回复(0)