React创建组件的三种方式及其区别


Posted in Javascript onJanuary 12, 2017

React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归;具体的三种方式:

  • 函数式定义的无状态组件
  • es5原生方式React.createClass定义的组件
  • es6形式的extends React.Component定义的组件

虽然有三种方式可以定义react的组件,那么这三种定义组件方式有什么不同呢?或者说为什么会出现对应的定义方式呢?下面就简单介绍一下。

无状态函数式组件

创建无状态函数式组件形式是从React 0.14版本开始出现的。它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到要state状态的操作。具体的无状态函数式组件,其官方指出:

在大部分React代码中,大多数组件被写成无状态的组件,通过简单组合可以构建成其他的组件等;这种通过多个简单然后合并成一个大应用的设计模式被提倡。

无状态函数式组件形式上表现为一个只带有一个render方法的组件类,通过函数形式或者ES6 arrow function的形式在创建,并且该组件是无state状态的。具体的创建形式如下:

function HelloComponent(props, /* context */) {
 return <div>Hello {props.name}</div>
}
ReactDOM.render(<HelloComponent name="Sebastian" />, mountNode)

无状态组件的创建形式使代码的可读性更好,并且减少了大量冗余的代码,精简至只有一个render方法,大大的增强了编写一个组件的便利,除此之外无状态组件还有以下几个显著的特点:

1.组件不会被实例化,整体渲染性能得到提升

因为组件被精简成一个render方法的函数来实现的,由于是无状态组件,所以无状态组件就不会在有组件实例化的过程,无实例化过程也就不需要分配多余的内存,从而性能得到一定的提升。

2.组件不能访问this对象

无状态组件由于没有实例化过程,所以无法访问组件this中的对象,例如:this.ref、this.state等均不能访问。若想访问就不能使用这种形式来创建组件

3.组件无法访问生命周期的方法

因为无状态组件是不需要组件生命周期管理和状态管理,所以底层实现这种形式的组件时是不会实现组件的生命周期方法。所以无状态组件是不能参与组件的各个生命周期管理的。

4.无状态组件只能访问输入的props,同样的props会得到同样的渲染结果,不会有副作用

无状态组件被鼓励在大型项目中尽可能以简单的写法来分割原本庞大的组件,未来React也会这种面向无状态组件在譬如无意义的检查和内存分配领域进行一系列优化,所以只要有可能,尽量使用无状态组件

React.createClass

`React.createClass`是react刚开始推荐的创建组件的方式,这是ES5的原生的JavaScript来实现的React组件,其形式如下:

var InputControlES5 = React.createClass({
 propTypes: {//定义传入props中的属性各种类型
 initialValue: React.PropTypes.string
 },
 defaultProps: { //组件默认的props对象
 initialValue: ''
 },
 // 设置 initial state
 getInitialState: function() {//组件相关的状态对象
 return {
 text: this.props.initialValue || 'placeholder'
 };
 },
 handleChange: function(event) {
 this.setState({ //this represents react component instance
 text: event.target.value
 });
 },
 render: function() {
 return (
 <div>
 Type something:
 <input onChange={this.handleChange} value={this.state.text} />
 </div>
 );
 }
});
InputControlES6.propTypes = {
 initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
 initialValue: ''
};

与无状态组件相比,React.createClass和后面要描述的React.Component都是创建有状态的组件,这些组件是要被实例化的,并且可以访问组件的生命周期方法。但是随着React的发展,React.createClass形式自身的问题暴露出来:

  • React.createClass会自绑定函数方法(不像React.Component只绑定需要关心的函数)导致不必要的性能开销,增加代码过时的可能性。
  • React.createClass的mixins不够自然、直观;React.Component形式非常适合高阶组件(Higher Order Components--HOC),它以更直观的形式展示了比mixins更强大的功能,并且HOC是纯净的JavaScript,不用担心他们会被废弃。

React.Component

React.Component是以ES6的形式来创建react的组件的,是React目前极为推荐的创建有状态组件的方式,最终会取代React.createClass形式;相对于 React.createClass可以更好实现代码复用。将上面React.createClass的形式改为React.Component形式如下:

class InputControlES6 extends React.Component {
 constructor(props) {
 super(props);
 // 设置 initial state
 this.state = {
 text: props.initialValue || 'placeholder'
 };
 // ES6 类中函数必须手动绑定
 this.handleChange = this.handleChange.bind(this);
 }
 handleChange(event) {
 this.setState({
 text: event.target.value
 });
 }
 render() {
 return (
 <div>
 Type something:
 <input onChange={this.handleChange}
 value={this.state.text} />
 </div>
 );
 }
}
InputControlES6.propTypes = {
 initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
 initialValue: ''
};

React.createClass与React.Component区别

根据上面展示代码中二者定义组件的语法格式不同之外,二者还有很多重要的区别,下面就描述一下二者的主要区别。

函数this自绑定

React.createClass创建的组件,其每一个成员函数的this都有React自动绑定,任何时候使用,直接使用this.method即可,函数中的this会被正确设置。

const Contacts = React.createClass({ 
 handleClick() {
 console.log(this); // React Component instance
 },
 render() {
 return (
 <div onClick={this.handleClick}></div>
 );
 }
});

React.Component创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。

class Contacts extends React.Component { 
 constructor(props) {
 super(props);
 }
 handleClick() {
 console.log(this); // null
 }
 render() {
 return (
 <div onClick={this.handleClick}></div>
 );
 }

当然,React.Component有三种手动绑定方法:可以在构造函数中完成绑定,也可以在调用时使用method.bind(this)来完成绑定,还可以使用arrow function来绑定。拿上例的handleClick函数来说,其绑定可以有:

constructor(props) {
 super(props);
 this.handleClick = this.handleClick.bind(this); //构造函数中绑定
 }

  <div onClick={this.handleClick.bind(this)}></div> //使用bind来绑定

   <div onClick={()=>this.handleClick()}></div> //使用arrow function来绑定

组件属性类型propTypes及其默认props属性defaultProps配置不同

React.createClass在创建组件时,有关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是使用getDefaultProps的方法来获取默认组件属性的

const TodoItem = React.createClass({
 propTypes: { // as an object
 name: React.PropTypes.string
 },
 getDefaultProps(){ // return a object
 return {
 name: '' 
 }
 }
 render(){
 return <div></div>
 }
})

React.Component在创建组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。对应上面配置如下:

class TodoItem extends React.Component {
 static propTypes = {//类的静态属性
 name: React.PropTypes.string
 };
 static defaultProps = {//类的静态属性
 name: ''
 };
 ...
}

组件初始状态state的配置不同

React.createClass创建的组件,其状态state是通过getInitialState方法来配置组件相关的状态;

React.Component创建的组件,其状态state是在constructor中像初始化组件属性一样声明的。

const TodoItem = React.createClass({
 // return an object
 getInitialState(){ 
 return {
 isEditing: false
 }
 }
 render(){
 return <div></div>
 }
})
class TodoItem extends React.Component{
 constructor(props){
 super(props);
 this.state = { // define this.state in constructor
 isEditing: false
 } 
 }
 render(){
 return <div></div>
 }
}

Mixins的支持不同

Mixins(混入)是面向对象编程OOP的一种实现,其作用是为了复用共有的代码,将共有的代码通过抽取为一个对象,然后通过Mixins进该对象来达到代码复用。

React.createClass在创建组件时可以使用mixins属性,以数组的形式来混合类的集合。

var SomeMixin = { 
 doSomething() {
 }
};
const Contacts = React.createClass({ 
 mixins: [SomeMixin],
 handleClick() {
 this.doSomething(); // use mixin
 },
 render() {
 return (
 <div onClick={this.handleClick}></div>
 );
 }
});

但是遗憾的是React.Component这种形式并不支持Mixins,至今React团队还没有给出一个该形式下的官方解决方案;但是React开发者社区提供一个全新的方式来取代Mixins,那就是Higher-Order Components

如何选择哪种方式创建组件

由于React团队已经声明React.createClass最终会被React.Component的类形式所取代。但是在找到Mixins替代方案之前是不会废弃掉React.createClass形式。所以:

能用React.Component创建的组件的就尽量不用React.createClass形式创建组件。

除此之外,创建组件的形式选择还应该根据下面来决定:

1、只要有可能,尽量使用无状态组件创建形式。

2、否则(如需要state、生命周期方法、ref等),使用`React.Component`这种es6形式创建组件

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
通过JAVASCRIPT读取ASP设定的COOKIE
Feb 15 Javascript
jQuery 行级解析读取XML文件(附源码)
Oct 12 Javascript
JavaScript设置IFrame高度自适应(兼容各主流浏览器)
Jun 05 Javascript
jquery+php实现搜索框自动提示
Nov 28 Javascript
jQuery的观察者模式详解
Dec 22 Javascript
JS+CSS实现表格高亮的方法
Aug 05 Javascript
快速掌握WordPress中加载JavaScript脚本的方法
Dec 17 Javascript
微信公众平台开发教程(五)详解自定义菜单
Dec 02 Javascript
jQuery为DOM动态追加事件的方法
Feb 16 Javascript
vue构建动态表单的方法示例
Sep 22 Javascript
layui数据表格实现重载数据表格功能(搜索功能)
Jul 27 Javascript
js实现自动播放匀速轮播图
Feb 06 Javascript
微信小程序Server端环境配置详解(SSL, Nginx HTTPS,TLS 1.2 升级)
Jan 12 #Javascript
JavaScript利用Date实现简单的倒计时实例
Jan 12 #Javascript
React组件的三种写法总结
Jan 12 #Javascript
JQuery异步提交表单与文件上传功能示例
Jan 12 #Javascript
jQuery命名空间与闭包用法示例
Jan 12 #Javascript
jquery实现百叶窗效果
Jan 12 #Javascript
基于JavaScript实现带缩略图的轮播效果
Jan 12 #Javascript
You might like
PHP $_SERVER详解
2009/01/16 PHP
PHP动态创建Web站点的方法
2011/08/14 PHP
PHP获取Exif缩略图的方法
2015/07/13 PHP
PHP+JS三级菜单联动菜单实现方法
2016/02/24 PHP
Yii2实现让关联字段支持搜索功能的方法
2016/08/10 PHP
PHP调用接口用post方法传送json数据的实例
2018/05/31 PHP
Laravel程序架构设计思路之使用动作类
2018/06/07 PHP
Jquery 实现Tab效果 思路是js思路
2010/03/02 Javascript
jquery autocomplete自动完成插件的的使用方法
2010/08/07 Javascript
javascript instanceof 内部机制探析
2010/10/15 Javascript
js获取单选框或复选框值及操作
2012/12/18 Javascript
event对象获取方法总结在google浏览器下测试
2013/11/03 Javascript
javascript arguments使用示例
2014/12/16 Javascript
JavaScript 浏览器对象模型BOM使用介绍
2015/04/13 Javascript
浅析Bootstrap缩略图组件与警示框组件
2016/04/29 Javascript
node学习记录之搭建web服务器教程
2017/02/16 Javascript
详解Angular2表单-模板驱动的表单(Template-Driven Forms)
2017/08/04 Javascript
使用veloticy-ui生成文字动画效果
2018/02/08 Javascript
angularJs 表格添加删除修改查询方法
2018/02/27 Javascript
vue+echarts实现可拖动节点的折线图(支持拖动方向和上下限的设置)
2019/04/12 Javascript
JS拖动选择table里的单元格完整实例【基于jQuery】
2019/05/28 jQuery
python爬取w3shcool的JQuery课程并且保存到本地
2017/04/06 Python
使用Python &amp; Flask 实现RESTful Web API的实例
2017/09/19 Python
python实现多层感知器
2019/01/18 Python
python实现在cmd窗口显示彩色文字
2019/06/24 Python
python爬虫 模拟登录人人网过程解析
2019/07/31 Python
python线程的几种创建方式详解
2019/08/29 Python
Python异步编程之协程任务的调度操作实例分析
2020/02/01 Python
美国在线宠物商店:Chewy
2019/01/12 全球购物
初中生三年学习生活的自我评价
2013/11/03 职场文书
清洁工岗位职责
2014/01/29 职场文书
一份没有按时交货失信于客户的检讨书
2014/09/19 职场文书
2014年小学教师工作总结
2014/11/10 职场文书
组织委员竞选稿
2015/11/21 职场文书
如何用Node.js编写内存效率高的应用程序
2021/04/30 Javascript
mysql中int(3)和int(10)的数值范围是否相同
2021/10/16 MySQL