浅谈React高阶组件


Posted in Javascript onMarch 28, 2018

前段时间在工作中写Hybrid页面时遇到了这样的一个场景,公司需要一系列的活动组件,在每个组件注册的时候都需要调用App端提供的一个接口。一开始也考虑了几种方式,包括mixin、组件继承以及react高阶组件。但经过了种种衡量,最后选择使用了高阶组件的做法。

那什么是高级组件?首先你得先了解请求ES6中的class只是语法糖,本质还是原型继承。能够更好的进行说明,我们将不会修改组件的代码。而是通过提供一些能够包裹组件的组件, 并通过一些额外的功能来增强组件。这样的组件我们称之为高阶组件(Higher-Order Component)。

1、Mixins的缺点

React官方已不推荐使用Mixins的技术来实现代码的重用,Mixins技术有一系列的缺点,首先Mixins会造成命名冲突,我们通过以下的方式来注入Mixins:

var myMixins = require('myMixins');

var Button = React.createClass({
  mixins: [myMixins],
  
  // ...
})

如果你需要注入多个mixins,其中一个是自己的,另外的可能是第三方的。那有可能在两个mixins里使用了相同名称的方法,这会使得其中的一个不起作用,而你能做的只有修改其中一个方法的名称。另一方面,一个mixins一开始可能是非常简单的,仅仅需要实现某一个功能,但当业务越加的复杂,需要往其中加入更多的方法的时候,就会变得非常复杂。要深入了解mixins的缺点,可以查看官方博客。

2、组件继承

对于我自己来说这种方法以前使用的比较多,先创建一个BaseComponent,在其中实现一系列公共的方法,其后的每个组件都继承于这个组件,但缺点是不够灵活,在基础组件中只能实现一些比较固定的方法,而对于每个组件的定制化会有很大的限制。

3、React高阶组件

由于mixins的一系列缺点,React官方也意识到使用mixins所带来的痛点远远高于技术本身产生的优点,而高阶组件便可以代替mixins,而且当深入之后它还有着更加丰富的用法。

高阶组件(HOC)是React中对组件逻辑进行重用的高级技术。但高阶组件本身并不是React API。它只是一种模式,这种模式是由React自身的组合性质必然产生的。

高阶函数

说到高阶组件,就先得说到高阶函数了,高阶函数是至少满足下列条件的函数:

1、接受一个或多个函数作为输入
2、输出一个函数

在javascript这门函数为一等公民的语言中,高阶函数的使用还是非常之多的,像我们平时的回调函数等等,都用到了高阶函数的知识。我们先来看一个简单的高阶函数

var fun = function(x, y) {
  return x + y;
}

fun是一个函数,下面我们将整个函数作为参数传递给另一个函数

var comp = function(x, y, f) {
  return f(x,y);
}

验证一下

comp(1,2,fun) // 3

高阶组件定义

类比高阶函数的定义,高阶组件就是接受一个组件作为参数,在函数中对组件做一系列的处理,随后返回一个新的组件作为返回值。

我们先定义一个高阶组件BaseActivity

const BaseActivity = (WrappedComponent) => {
 return class extends Component {
  render() {
   return (
    <section>
     <div>我的包裹组件</div>
     <WrappedComponent />
    </section>
    
   )
  }
 }
}

组件接受一个被包裹的组件作为参数,返回了一个经过处理的匿名组件。

在其他组件中使用这个高阶组件

class Example extends React.PureComponent {
 constructor(props) {
  super(props);
  this.state = {
   width: '100%',
   height: '100%'
  }
 }

 componentWillMount() {
  if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
   return;
  } else {
   this.setState({
    width: '375px',
    height: '640px'
   })
  }
 }

 render() {
  let { width, height } = this.state;
  return (
   <div className="activity">
    <div className="activity-content" style={{ width, height }}>
     <button className="btn">参加活动</button>
    </div>
   </div>
  )
 }
}

export default BaseActivity(Example);

具体用法就是在export 组件的时候,使用BaseActivity函数来包裹这个组件,看下输出的react dom内容

浅谈React高阶组件

在Example组件外面包裹了一个匿名组件。

参数

既然高阶组件是一个函数,我们就可以向里面传递我们需要的参数

const BaseActivity = (WrappedComponent, title) => {
 return class extends Component {
  render() {
   return (
    <section>
     <div>{title}</div>
     <WrappedComponent />
    </section>
    
   )
  }
 }
}

在Example中这样export

export default BaseActivity(Example, '这是高阶组件的参数');

我们看下输出的react dom

浅谈React高阶组件

可以看到参数已经传递进去了。

当然还可以这样用(柯里化)

const BaseActivity (title) => (WrappedComponent) => {
 return class extends Component {
  render() {
   return (
    <section>
     <div>{title}</div>
     <WrappedComponent />
    </section>
    
   )
  }
 }
}

在Example中这样export

export default BaseActivity('这是高阶组件的参数')(Example);

这种用法在ant-design的表单以及redux的connect中我们都可以看到

// ant
const WrappedDemo = Form.create()(Demo)

// redux
export default connect(mapStateToProps, mapDispatchToProps)(Counter)

高阶组件还可以扩展原组件的props属性,如下所示:

const BaseActivity (title) => (WrappedComponent) => {
 return class extends Component {
  render() {
   const newProps = {
     id: Math.random().toString(8)
   }
   return (
    <section>
     <div>{title}</div>
     <WrappedComponent {...this.props} {...newProps}/>
    </section>
   )
  }
 }
}

看下输出的react dom

浅谈React高阶组件

高阶组件的缺点

高阶组件也有一系列的缺点,首先是被包裹组件的静态方法会消失,这其实也是很好理解的,我们将组件当做参数传入函数中,返回的已经不是原来的组件,而是一个新的组件,原来的静态方法自然就不存在了。如果需要保留,我们可以手动将原组件的方法拷贝给新的组件,或者使用hoist-non-react-statics之类的库来进行拷贝。

结语

高阶函数对于初学者来说可能不太好理解,但当你深入其中,了解其中的原理之后,我们可以使用高阶函数来完成很多的工作。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript技巧之不要用for in语句对数组进行遍历
Oct 20 Javascript
xml转json的js代码
Aug 28 Javascript
Jquery UI震动效果实现原理及步骤
Feb 04 Javascript
AngularJS辅助库browserTrigger用法示例
Nov 03 Javascript
[js高手之路]设计模式系列课程-发布者,订阅者重构购物车的实例
Aug 29 Javascript
手把手教你使用vue-cli脚手架(图文解析)
Nov 08 Javascript
详解node.js 下载图片的 2 种方式
Mar 02 Javascript
vue 开发一个按钮组件的示例代码
Mar 27 Javascript
vue.js实现点击后动态添加class及删除同级class的实现代码
Apr 04 Javascript
highCharts提示框中显示当前时间的方法
Jan 18 Javascript
js实现html滑动图片拼图验证
Jun 24 Javascript
vue修饰符.capture和.self的区别
Apr 22 Vue.js
vue数据控制视图源码解析
Mar 28 #Javascript
jQuery+ajax读取json数据并按照价格排序示例
Mar 28 #jQuery
vue 开发一个按钮组件的示例代码
Mar 27 #Javascript
vue-cli脚手架-bulid下的配置文件
Mar 27 #Javascript
vue2中使用less简易教程
Mar 27 #Javascript
浅谈Vue内置component组件的应用场景
Mar 27 #Javascript
js中apply和Math.max()函数的问题及区别介绍
Mar 27 #Javascript
You might like
新手配置 PHP 调试环境(IIS+PHP+MYSQL)
2007/01/10 PHP
使用YUI+Ant 实现JS CSS压缩
2014/09/02 PHP
PHP获取youku视频真实flv文件地址的方法
2014/12/23 PHP
php生成唯一数字id的方法汇总
2015/11/18 PHP
PHP 5.6.11 访问SQL Server2008R2的几种情况详解
2016/08/08 PHP
PHP基于堆栈实现的高级计算器功能示例
2017/09/15 PHP
Jquery插件写法笔记整理
2012/09/06 Javascript
jquery多选项卡效果实例代码(附效果图)
2013/03/23 Javascript
node.js中使用socket.io制作命名空间
2014/12/15 Javascript
Jquery实现地铁线路指示灯提示牌效果的方法
2015/03/02 Javascript
使用javascript提交form表单方法汇总
2015/06/25 Javascript
jQuery中的ready函数与window.onload谁先执行
2016/06/21 Javascript
D3.js实现散点图和气泡图的方法详解
2016/09/21 Javascript
解决给dom元素绑定click等事件无效问题的方法
2017/02/17 Javascript
Nodejs中crypto模块的安全知识讲解
2018/01/03 NodeJs
JavaScript实现的贝塞尔曲线算法简单示例
2018/01/30 Javascript
如何优雅地在Node应用中进行错误异常处理
2019/11/25 Javascript
jquery自定义组件实例详解
2020/12/31 jQuery
[56:18]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#2 MVP.Phx VS Fnatic第二局
2016/03/05 DOTA
python获取android设备的GPS信息脚本分享
2015/03/06 Python
python 计算两个日期相差多少个月实例代码
2017/05/24 Python
Python之Scrapy爬虫框架安装及使用详解
2017/11/16 Python
Python遍历文件夹 处理json文件的方法
2019/01/22 Python
Python 列表去重去除空字符的例子
2019/07/20 Python
python安装本地whl的实例步骤
2019/10/12 Python
python统计文章中单词出现次数实例
2020/02/27 Python
Pytorch高阶OP操作where,gather原理
2020/04/30 Python
Python wordcloud库安装方法总结
2020/12/31 Python
CSS3的resize属性使用初探
2015/09/27 HTML / CSS
计算机操作自荐信
2013/12/07 职场文书
客户服务经理岗位职责
2014/01/29 职场文书
农民工工资承诺书范文
2014/03/31 职场文书
作风整顿个人剖析材料
2014/10/06 职场文书
小学教师个人总结
2015/02/05 职场文书
八一建军节主持词
2015/07/01 职场文书
2015年迎新晚会策划书
2015/07/16 职场文书