React高阶组件

React高阶组件探秘

Posted by wang chong on April 14, 2019

什么是高阶函数

函数是一等公民

函数是一等公民的意思是:函数和其他数据类型是一样的,函数既可以保存在数组中又可以保存在对象中,函数也可以向其他数据类型一样作为另一个函数的参数,和其他数据类型处于同等地位。

那么什么是高阶函数?

当一个函数接受一个函数作为参数,经过一系列处理之后再返回一个函数,这样的函数叫做高阶函数。

高阶函数可以说是函数的增强剂,传入一个函数,返回增强后的函数。

高阶组件

高阶组件(High Order Component)可以说也是高阶函数,只是增强剂是一个组件,被增强的也组件,返回的也是组件。

咿? 我写的是class组件,怎么是函数呢?可以来验证以下。

ES6的class是语法糖本质上是function。

高阶组件的作用

当一个组件不具有某些功能的时候,可以通过HOC组件把相应的功能加持在当前组件上。相当于对组件的一种增强。

同时还可以抽离组件中公共的部分,通过高阶组件把所需要的东西附加上去。

高阶组件工厂模式

在构建高阶组件的时候,如果需要一起其他的配置或者参数等,可以封装成高阶组件的工厂模式。

const HOCFactor = (...params) => {
    //这里返回函数为什么要有函数名?
    //为了函数调试错误,函数执行有一个函数的执行堆栈,写上函数名而不是用匿名函数,是为了能够更好的定位错误。
    return  HOCFactorer = (WrapperComponent) => {
        return class HOC extends Component{
            render(){
                return <WrapperComponent {...this.props} />
            }
        }
    } 
}

高阶组件的两种使用方式

从上文知道,高阶组件其实就是一个函数接受一个组件作为参数,再返回一个新的组件出来。自从ES6盛行之后,调用方式也有两种:

  • 一种是类的装饰其方式
  • 一种是函数的调用方式。
Decorator方式

ES6中类的装饰器可以修改类的行为,并且在编译阶段就会修改。其实装饰其就是一个函数,只不过加上了修饰就变成了再编译时期执行的函数。

@Test
class A{}
//等同于
A = Test(A) || A

接下来就是Test这个函数了,Test函数会指定第一个参数为对哪一个类进行装饰,也可以说成是目标类。

function Test(target){
    target.name="Decorator";
    return target;
}

如果想在装饰的时候传入一些参数,可以采用这样的写法

@Test("Hello Class")
class A{}
function Test(...args){
    return function test(target){
        target.name = args;
    }
}
//等同于
A = Test(A) || A;

使用装饰器构建高阶函数。使用上面工厂模式中的高阶函数。

@HOCFactor({})
class WrappedComponent extends Component{
    render(){
        return <p>普通组件</p>
    }
}

就这么简单。

函数调用方式使用

函数调用方式就很平常。平时写代码的时候调用函数的写法相同。

class WrappedComponent extends Component{
    render(){
        return <p>普通组件</p>
    }
};
WrappedComponent = HOCFactor({})(WrappedComponent);

多种高阶函数组合调用

当需要多种高阶函数组合调用的时候。两种高阶函数同样有两种办法。

Decorator

装饰器方式:如果对一个类定义多个装饰器,对于工厂模式来说是由外向内触发,而对于装饰器来说是由内向外触发。

import React,{Component} from "react";

const HOCFactor = (...params) => {
    console.log("工厂1")
    return  function HOCFactorer(WrapperComponent){
        console.log("Decorator1")
        return class HOC extends Component{
            render(){
                return (
                    <div>
                        高阶组件
                        <WrapperComponent {...this.props} />
                    </div>
                )
            }
        }
    } 
}

const HOCFactor1 = (...params) => {
    console.log("工厂2")
    return function (WrapperComponent){
        console.log("Decorator2")
        return class HOC extends Component {
            render(){
                return (
                    <div>
                        高阶组件1
                        <WrapperComponent {...this.props}/>
                    </div>
                )
            }
        }
    }
}

@HOCFactor({})
@HOCFactor1()
class WrappedComponent extends Component{
    render(){
        return <p>普通组件</p>
    }
}

函数调用方式

函数调用方式调用多个高阶函数,需要使用一个组合函数。

const compose = (...fns) => fns.reduce((f,g) => (...args) => f(g(...args)));

还是使用上面两个高阶函数和组件。

const composeComponent = compose(HOCFactor(),HOCFactor1())
WrappedComponent = composeComponent(WrappedComponent)

总结

高阶函数的奇妙可以解决我们很多问题,给组件添加功能,抽离公共能力等等,但是高阶组件的出现明显的增加了组件间的复杂程度,让组件嵌套的更深了。还是需要在业务中按需选择吧。