说明与目录

 在学习本章内容之前,最好是具备react中‘插槽(children)’及‘组合与继承’ 这两点的知识积累。
详情请参照React 精要面试题讲解(四) 组合与继承不得不说的秘密。
哦不好意思忘记了,四还没写呢。==!回头补上。
__首先,我们要知道高阶组件能够做到什么: 对复用UI、数据逻辑等进行封装,对参数组件进行制式处理,从而让参数组建具备特定的ui或功能__
那么本节的学习目录:
  1. 高阶函数的认知

  2. 类的修饰器(decorator)的认知(类比高阶函数)

  3. 高阶组件的认知(类比修饰器)

  4. 高阶组件的两种形式(类比插槽)

  5. 高阶组件之组合(代理)类型的高阶组件

  6. 高阶组件之继承类型的高阶组件

  7. 高阶组件的认知总结

    必须深刻认知,以上内容是循序渐进且相互关联的关系,按照流程,我们将彻底把高阶组件安排的明明白白,玩个透彻。

1. 高阶函数的认知

在本系列之前的学习中,你应当明白——组件的本质是函数。
那么什么是高阶函数?
高阶函数也是一个函数,__它接受函数为参数,返回处理过后的函数或者一个新函数__。
那么我们知道,高阶函数的作用是对参数函数进行统一的加工处理。
形如:
    //这里我们写了一个函数作为之后的参数
//思考一下为什么把参数函数定义在上面
function testedFunc(){
this.a = 1;
} // 在此定义一个高阶函数
function highOrderFunc(func){
func.prototype.aaa = 3;
return func;
} //这里测试一下我们写的高阶函数
var newFunc = highOrderFunc(testedFunc); //打印看看处理后的函数原型及实例
console.log(newFunc.prototype,1);
console.log(new newFunc(),2);

(别那么懒,赶紧复制粘贴f12)

打印结果如下:



那么我们知道了,高阶函数 作用是 处理(加工)传入的函数,以达成某种目的…

2. 类的修饰器(decorator)的认知

ES6增添了class类,我们知道,类的本质也是函数。

     class testClass{
a = 1;
}
console.log( typeof testClass)
打印结果如下:

那么类的修饰器——decorator 是个怎样的东西咧?
__类的修饰器是es6的提案之一,在es7标准中实现。 修饰器也是一个函数,把传入的原有类修饰一下,return 出处理后的类或新类。__
这时候我们脑海中应该闪过一个词——高阶类…(???黑人问号)
不觉得太难听了吗?

ok,我们还是以代码来演示一下:

    //注意,下面这种@xx的写法是修饰器的标准写法,是属于es7的产物,要用babel哦~

    //定义一个修饰器decF
function decF(adornedClass){
return class extends adornedClass{
b= 2
}
} // 使用方式1 : @decF
@decF
class foo{
a = 1
}
console.log( new foo(),1) class bar{
a='bar'
}
// 使用方式2 : decF();
const newBar = decF(bar);
console.log( new newBar(),2);

打印如下:

瞧啊,修饰器就是这么个东西。

要注意的是,类的修饰器能否修饰函数?为什么?

// 可以自己去找答案,再讲别的就跑题了。


3. 高阶组件的认知(类比修饰器)

那么经过类的修饰器的认知,高阶组件的概念就很明朗了。

React高阶组件(high-order-component,简称hoc)就是一个类的修饰器啊…它接受一个组件类为参数,返回出一个新的组件类;

形如:

   // 用法1 高阶函数式写法
hoc(WrapedComponent);
// 用法2 decorator 修饰器写法
@hoc
class A extends React.Component{
//...
}

大家有木有很眼熟啊 ?

ok, 我们写一个常规的高阶组件并暴露出去;

   export default  WrapedComponent  => class  NewComponent extends React.Component{

         render(){
return <WrapedComponent a = '添加了一个属性' />
}
}

这种箭头函数的写法好理解吧。

如代码所示,我们写了一个高阶组件,返回的新组件 NewComponent里,用组合的形式使用了传入的组件WrapedComponent。(所以不明白组合与继承的童鞋,赶紧补一补再来看啊)

这里有人问 connect为啥两个括号啊

 //形如
connect(func1,func2 )( WrapedComponent)

OK ,我们也手写一下它。

     export default (func1,func2)=>WrapedComponent=>class NewComponent extends React.Component{
// ....
}

这个两层箭头函数好理解吧?

顺便说下,一般像connect这样多嵌套了一层的高阶函数,我称之为二阶高阶函数。此后类推,三个括号就叫三阶高阶函数…


4. 高阶组件的两种形式(类比插槽)

同children 一样,高阶组件也存在组合(也可称之为代理)和继承两种形式。

那么高阶组件和children插槽有什么关系呢?

我们来类比以下代码:

  //写一个组合形式的具备插槽功能的组件Provider
class Provider extends React.Component{
render(){
return (
<div>
{this.props.children}
</div>
)
}
}
// 下面是使用的方式
import ComA from './ComA'
const useB = (<Provider > <ComA a='使用Provider时添加了a属性'/> </Provider >)
   // 写一个组合形式的高阶组件
const hocAddA = WrapedComponent => class NewComponent extends React.component{
render(){
return (
<div>
<WrapedComponent a ='定义hocAddA时添加了a属性'/>
</div>
)
}
}
// 我们来尝试使用它
const NewA = hocAddA(ComA);
// 或者
@hocAddA
class ComB ...

ok, 上述两种代码在使用后的表现几乎是一致的(同样实现了给ComA添加属性a的功能)。

但是注意,插槽(children)的实现,不关心插槽组件的功能变化。只是把插槽当作当前组件的子组件去使用(这就是组合)。

   //同样的,我现在这样使用
import ComA from './ComA'
const useB = (<Provider > <ComA b='使用Provider时添加了b属性'/> </Provider >)

而高阶函数,在定义时就写死了参数组件的功能变化。

传入组件,得出的组件只会添加属性a。

当然,我们也可以通过二阶高阶函数实现 用参数控制参数组件的功能变化:

  定义一个二阶高阶组件
const hocAddProps = props => WrapedComponent => class NewComponent extends React.Component{
render(){
return (
<div>
<WrapedComponent {...props}/>
</div>
)
}
}
// 于是我们这样使用它
const propsAdded = {
a: '添加了一个属性a',
b: ‘添加了一个属性b'
}
const NewA = hocAddProps(propsAdded)(ComA)

诸如此类。实际上组合形式的高阶组件能做到的事,用children基本都能做到。

那么组合形式的高阶组件和继承形式的高阶组件的区别在哪呢?

组合形式(也称之为代理形式): 返回的新组件,继承的还是React.Component,只是把参数组件作为新组件的子组件去使用,能够实现给参数组件进行包装、属性的增删改、状态抽离等功能.

继承形式: 返回的新组件,继承的是 参数组件 ,从而实现以参数组件为模版,改写参数组件的功能。

上述划重点,要考。

我们再回过头来思考类的修饰器——返回一个新的类或改写参数类。

是不是一样的道理啊。

所以说高阶组件啥的,还是js啊,最多加了jsx的语法嘛。

5. 高阶组件之组合(代理)类型的高阶组件

上述我们已经知道了组合(代理)类型的高阶组件的概念和思想,以及它能实现的功能。

那么我们上demo代码


import React,{Component,createRef} from 'react';
export default title=>WrapedComponent=> class NewComponent extends Component{
//抽离状态
state={
value:''
}
// 访问refs
myref=createRef();
handleInputChange=(e)=>{
this.setState({
value:e.target.value
})
} render(){
const {wap,...otherprops} = this.props;
const newProps = {
value:this.state.value,
onChange:this.handleInputChange
}
//包装组件
return (
<div>
我是组件NewComponent,是典型的代理形式的高阶组件,我除了做自己的事,还可以对 我的参数组件:
1增加/删减props 2抽离状态 3访问ref 4包装组件
<div>我的title:{title}</div>
<WrapedComponent {...otherprops} ref={this.myref} inputProps={newProps}/>
</div>
)
}
}

这里要单独说一下上述功能中的状态抽离。

状态抽离(状态提升): 把参数组件(即代理形式中使用的子组件)的状态提升到NewComponent(即代理形式中的当前组件,也就是父组件) 中,这样一来,子组件只负责UI渲染,而父组件通过props传递state实现数据的控制

也就是说, NewComponent 成为参数组件的容器组件,参数组建单纯作为UI组件

ps: 容器组件和UI组件的概念是相对的。 例如 把B的状态抽离到父组件A上,那么A相对于B来说是B的容器组件,要这么去理解。后续讲react-redux中会提到。


6. 高阶组件之继承类型的高阶组件

同样的,上述我们已经知道了 继承类型的高阶组件的概念和思想,那么我们也直接上demo代码

import React from  'react'

//这个是给返回的新组件起名用的函数,有兴趣可以结合调试器玩玩。
function getDisplayName(WrapedComponent){
return WrapedComponent.displayName||WrapedComponent.name||'component'
} export default color=>WrapedComponent=> class NewComponent extends WrapedComponent{
// static displayName = `E(${getDisplayName(Inconponent)})`
;
aaa = '我改写了参数组件中的aaa属性'
compoenentDidMount(){
console.log('我不仅可以改写属性和方法,我还能改写钩子')
}
render(){
const {wap,...otherprops} = this.props;
const element = super.render();
console.log(element);
const newStyle = {
color:element.type==='div'?color:null
}
const newProps = {
...otherprops,
style:newStyle
}
// 我甚至还改写了参数组件的UI
return React.cloneElement(element,newProps,element.props.children)
}
}

如上述代码所示(跟着敲一下啊懒虫),我们成功做到了以参数组件为模版,改写了参数组件中已定义的属性、方法、钩子,甚至UI,增添了参数组件中未定义的属性、方法、钩子等。

当然,同官方文档中 ‘组合和继承’ 这一章中的思想一致,绝大部分情况下,我们用不到继承类型的高阶组件,也不提倡这种形式的用法(其实我个人觉得挺好玩的)。


7. 高阶组件的认知总结

那么我们通过以上学习,已经完完整整掌握了高阶组件的使用。
在日常项目中,我们也可以在合适的场景中使用高阶组件完成对应的需求。
回顾最上面提到过的高阶组件的使用场景:
__对复用UI、数据逻辑等进行封装,对参数组件进行制式处理,从而让参数组建具备特定的ui或功能__ 再回顾下上述讲到过的高阶函数,类的修饰器等——
你get到了吗? 面试中会问到高阶组件的问题,消化掉这一篇,那么你便可以连续不断的给面试官讲上半个小时征服他。

最后,如果本章内容对你的react学习有帮助,记得点个关注,等待更新哦。

React 精要面试题讲解(五) 高阶组件真解的更多相关文章

  1. React 精要面试题讲解(一) 单向数据流

    react 单向数据流概念 'react框架是怎样的数据流向?'||'react单向数据流是怎样的概念 ?' 解答这个问题之前,我们首先得知道,js框架是个怎样的概念. 框架:具备一定**编程思想** ...

  2. React躬行记(10)——高阶组件

    高阶组件(High Order Component,简称HOC)不是一个真的组件,而是一个没有副作用的纯函数,以组件作为参数,返回一个功能增强的新组件,在很多第三方库(例如Redux.Relay等)中 ...

  3. React 精要面试题讲解(二) 组件间通信详解

    单向数据流与组件间通信 上文我们已经讲述过,react 单向数据流的原理和简单模拟实现.结合上文中的代码,我们来进行这节面试题的讲解: react中的组件间通信. 那么,首先我们把看上文中的原生js代 ...

  4. 聊聊React高阶组件(Higher-Order Components)

    使用 react已经有不短的时间了,最近看到关于 react高阶组件的一篇文章,看了之后顿时眼前一亮,对于我这种还在新手村晃荡.一切朝着打怪升级看齐的小喽啰来说,像这种难度不是太高同时门槛也不是那么低 ...

  5. React文档(二十四)高阶组件

    高阶组件(HOC)是React里的高级技术为了应对重用组件的逻辑.HOCs本质上不是React API的一部分.它是从React的组合性质中显露出来的模式. 具体来说,一个高阶组件就是一个获取一个组件 ...

  6. 函数式编程与React高阶组件

    相信不少看过一些框架或者是类库的人都有印象,一个函数叫什么creator或者是什么什么createToFuntion,总是接收一个函数,来返回另一个函数.这是一个高阶函数,它可以接收函数可以当参数,也 ...

  7. React中的高阶组件

    高阶组件(HOC, High-Order Component)是React中用于重组组件逻辑的高级技术,是一种编程模式而不是React的api. 直观来讲,高阶组件是以某一组件作为参数返回一个新组件的 ...

  8. React——高阶组件

    1.在React中higher-order component (HOC)是一种重用组件逻辑的高级技术.HOC不是React API中的一部分.HOC是一个函数,该函数接收一个组件并且返回一个新组件. ...

  9. react 高阶组件的 理解和应用

    高阶组件是什么东西 简单的理解是:一个包装了另一个基础组件的组件.(相对高阶组件来说,我习惯把被包装的组件称为基础组件) 注意:这里说的是包装,可以理解成包裹和组装: 具体的是高阶组件的两种形式吧: ...

随机推荐

  1. 百度APP移动端网络深度优化实践分享(二):网络连接优化篇

    本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<二>连接优化>,感谢原作者的无私分享. 一.前言 在<百度APP移动端网 ...

  2. Oracle和Mysql获取uuid的方法对比

    场景:orm框架用mybatis,需要往数据库新增一条数据,用Oracle和mysql数据库分别需要怎么实现? mysql方法,用mysql提供的uuid函数 <insert id=" ...

  3. 那些优秀的.NET开发者----汪宇杰:从重视细节,到成就技术专家

    初识汪宇杰 在长沙.NET技术社区筹建过程中,溪源有幸认识来自上海的MVP汪宇杰Edi Wang.在中国众多的微软MVP中,Edi Wang作为一名九零后,也是一位年轻而充满才气的开发者,或许他或许外 ...

  4. JavaScript夯实基础系列(三):this

      在JavaScript中,函数的每次调用都会拥有一个执行上下文,通过this关键字指向该上下文.函数中的代码在函数定义时不会执行,只有在函数被调用时才执行.函数调用的方式有四种:作为函数调用.作为 ...

  5. vue项目首屏加载优化实战

    问题 单页面应用的一个问题就是首页加载东西过多,加载时间过长.特别在移动端,单页面应用的首屏加载优化更是绕不开的话题.下面我会写出我在项目中做的一些优化,希望大家能够相互讨论,共同进步. 我的项目vu ...

  6. Spring Cloud Alibaba 新版本发布:众多期待内容整合打包加入!

    在Nacos 1.0.0 Release之后,Spring Cloud Alibaba也终于发布了最新的版本.该版本距离上一次发布,过去了整整4个月!下面就随我一起看看,这个大家期待已久的版本都有哪些 ...

  7. 你觉得 .NET 性能低,可能只是因为你的能力低

    by Conmajia 本文由以下大佬赞助 加入赞助者行列 {{ sponsor.name }} 感恩,你们的赞助让我在抓耳挠腮写文章时不至于断了香烟. var s = [{ name: '◎梦想起航 ...

  8. Web 性能优化:Preload与Prefetch的使用及在 Chrome 中的优先级

    摘要: 理解Preload与Prefetch. 原文:Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级 作者:前端小智 Fundebug经授权转载,版权归原作者所 ...

  9. 华为6.0系统设备最完美激活Xposed框架的经验

    对于喜欢玩手机的伙伴而言,经常会使用上Xposed框架及种种功能强大的模块,对于5.0以下的系统版本,只要手机能获得root权限,安装和激活Xposed框架是非常轻松的,但随着系统版本的迭代,5.0以 ...

  10. Python-函数小结

    原文出处,如有侵权,请联系删除. 用户自定义.py文件 如果你已经把my_abs()的函数定义保存为abstest.py文件了,那么,可以在该文件的当前目录下启动Python解释器,用from abs ...