当前位置: 首页 > Web前端 > HTML5

React高阶组件简单讲解

时间:2023-04-05 16:00:29 HTML5

前言“高阶”这个词听起来很唬人,因为大学高等数学课程中的高阶方程让人抓狂,以至于接触“高阶”概念的人-levelcomponents”,我第一次误以为是一些深刻的思考和复杂的逻辑。但是相信当你学完并在生产环境中广泛使用之后,你会发现这个所谓的“高级组件”真的一点都不高级,非常简单易懂。本文通过回答三个问题,带你深入理解React高阶组件。1.为什么我们需要高阶组件?2、什么是高阶组件?3.高层组件如何实现?1.为什么我们需要高阶组件?问题很简单,为什么我们需要react/vue/angular?使用该框架的核心原因之一是为了提高开发效率和早点下班。同理,react高阶组件让我们写出更容易维护的react代码,也可以更早下班~比如ES6支持使用import/export拆分代码函数和模块,避免出现在一个文件中。“笨拙”的代码。同样,对于复杂的react组件,如果组件有几十个自定义函数,自然会被拆分,否则就会成为“捆绑”组件,那么如何优雅地拆分组件呢?React高级组件应运而生。使用ES5写react代码时,可以使用传统的Mixin模式进行拆分。新版react全面支持ES6,提倡用ES6写jsx,同时取消了Mixin。因此,高层组件越来越受到开源社区的关注。例如redux等知名第三方库大量使用了高层组件。2、什么是高阶组件?在回答这个问题之前,我们先来看一下本文的封面图。为什么作者要用初中生已经掌握的一元线性函数来表示这篇文章呢?显然,高阶函数是y=kx+b形式的东西,x是我们要变换的原始分量,y是变换后的输出分量。它是如何修改的?k和b是转换方法。这就是高级组件的基本原理,一点都不高级?举个例子让大家更好的理解:我们在写代码的时候需要进行加法计算,所以我们把加法计算的方法提炼出来写成一个加法函数,这个加法函数可以随处调用使用,从而减少工作量和代码量。而我们独立的随处可用的加法函数,类比的放在了react中,它是一个高阶组件。3.高层组件如何实现?通过以上问题的回答,我们知道高阶组件其实就是处理react组件的函数。那么我们如何实现高阶组件呢?有两种方法:1.属性代理2.反向继承第一种方法是属性代理,这是最常见的实现方式。处理后的组件的props和新的props被传递给新的组件。代码如下://WrappedComponentisProcessedcomponentfunctionHOC(WrappedComponent){returnclassHOCextendsComponent{render(){constnewProps={type:'HOC'};return

}}}@HOCclassOriginComponentextendsComponent{render(){return
这是原始组件
}}//constnewComponent=HOC(OriginComponent)CopycodePropertyproxy听起来好像很麻烦,但是从代码来看,就是利用HOC函数给处理过的组件WrappedComponent添加一些属性,并返回一个新的包含原始组件的组件。从chrome调试平台可以看到原来的组件已经被包裹了,并且有type属性:上面的代码使用了ES7的decorator装饰器来实现对OriginComponent组件的装饰增强,或者使用注释中的function方法达到同样的效果。使用属性代理的好处是可以将常用的方法隔离出来,多次复用。比如我们实现一个加法函数,那么我们把这个加法函数转化成上面提到的HOC函数的形式,然后在组件中包装其他组件来使用这个方法。第二种方法反向继承比较有意思,先看代码:functionHOC(WrappedComponent){returnclassHOCextendsWrappedComponent{//继承了传入的组件test1(){returnthis.test2()+5;}componentDidMount(){console.log('1');this.setState({number:2});}render(){//使用super调用传入组件的render方法returnsuper.render();}}}@HOCclassOriginComponentextendsComponent{constructor(props){super(props);this.state={number:1}}test2(){返回4;}componentDidMount(){console.log('2');}render(){return(
{this.state.number}{'and'}{this.test1()}这是原始组件
)}}//constnewComponent=HOC(OriginComponent)我们可能还有点迷糊,那我们先来分析一下“继承”这个关键词。什么是继承?新生成的HOC组件通过extends关键字获取传入组件OriginComponent的所有属性和方法,称为“继承”。也就是说,继承之后,HOC组件可以实现OriginComponent组件的所有功能,HOC可以拿到state和props进行修改,从而改变组件的行为,也就是所谓的“渲染劫持””。可以说,相对于房产经纪人实现的高阶组件,反向继承方式实现的高阶组件更强大,更个性化,适应的场景也更多。通过上面的代码,我们可以看到:首先:this.test1()输出9。为什么?因为在ES6中,当super以对象的方式调用父类方法时,super绑定了子类的this。所以当执行super.render()时,OriginComponent中的this指向了HOC组件,所以test1函数可以执行成功。第二:控制台输出1而不是2。为什么?首先,装饰器是在代码编译阶段执行的,所以HOC的render方法先于OriginComponent的render方法执行。而子组件HOC继承自父组件OriginComponent,两者有继承关系HOC.__proto__===OriginComponent,在执行componentDidMount方法的时候,子组件已经有这个方法,所以执行完就结束了,没有longer根据__proto__向上移动继续寻找。如果我们去掉子组件HOC中的componentDidMount方法,控制台会输出2。当我们有多个高阶组件需要同时增强一个组件时怎么办?我们可以这样写:@fun1@fun2@fun3classOriginComponentextendsComponent{...}复制代码也可以使用lodash的flowRight方法:constenchance=lodash.flowRight(fun1,fun2,fun3);@enchanceclassOriginComponent扩展组件{...}复制代码因为fun1fun2fun3都是处理类的函数,只要实现按顺序处理类即可。以上就是关于高阶组件的实现。为了查漏补缺,官方文档中有两个中肯的建议,这里摘录给大家:一句话总结,为了避免调试时因为高层组件的存在而HOC满屏(拿上面的代码为例),可以通过设置类的displayName属性来修改组件的名称。如果你对ES6中的继承有很好的理解,理解上面的文字应该会很简单。在ES6继承中,子类不能继承父类的静态方法,即使用static关键字定义的方法。如果子类要使用它,必须复制它才能使用。总结一下,高阶组件其实就是处理组件的函数。实现方式有两种:一种是属性代理,类似于一个变量的线性方程中的y=x+b。输入x是原始组件,参数b是你要添加或删除的属性/方法,y是最终输出的组件。二是反向继承,类似于一维方程中的y=kx+b,可以获取state和props用于渲染劫持(k),改变组件的行为。