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 相关文章推荐
基于jQuery的弹出警告对话框美化插件(警告,确认和提示)
Jun 10 Javascript
jQuery中not()方法用法实例
Jan 06 Javascript
javascript实现动态改变层大小的方法
May 14 Javascript
angularjs学习笔记之简单介绍
Sep 26 Javascript
基于HTML5上使用iScroll实现下拉刷新,上拉加载更多
May 21 Javascript
详解vue服务端渲染(SSR)初探
Jun 19 Javascript
Node做中转服务器转发接口
Oct 18 Javascript
关于laydate.js加载laydate.css路径错误问题解决
Dec 27 Javascript
基于vue.js 2.x的虚拟滚动条的示例代码
Jan 23 Javascript
微信小程序左滑动显示菜单功能的实现
Jun 14 Javascript
js限制input只能输入有效的数字(第一个不能是小数点)
Sep 28 Javascript
Vue-resource安装过程及使用方法解析
Jul 21 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中mysql_connect与mysql_pconncet的区别详解
2013/05/15 PHP
PHP图片库imagemagick安装方法
2014/09/23 PHP
PHP中仿制 ecshop验证码实例
2017/01/06 PHP
jquery.ui.progressbar 中文文档
2009/11/26 Javascript
Javascript 键盘keyCode键码值表
2009/12/24 Javascript
Javascript 异步加载详解(浏览器在javascript的加载方式)
2012/05/20 Javascript
js 动态加载事件的几种方法总结
2013/12/25 Javascript
jquery实现非叠加式的搜索框提示效果
2014/01/07 Javascript
javascript替换已有元素replaceChild()使用介绍
2014/04/03 Javascript
原生javascript实现获取指定元素下所有后代元素的方法
2014/10/28 Javascript
简介JavaScript中toUpperCase()方法的使用
2015/06/06 Javascript
深入理解bootstrap框架之入门准备
2016/10/09 Javascript
bootstrap fileinput 插件使用项目总结(经验)
2017/02/22 Javascript
TypeScript入门-基本数据类型
2017/03/28 Javascript
利用JS实现简单的瀑布流加载图片效果
2017/04/22 Javascript
JS去掉字符串末尾的标点符号及删除最后一个字符的方法
2017/10/24 Javascript
vue.js简单配置axios的方法详解
2017/12/13 Javascript
jQuery easyui datagird编辑行删除行功能的实现代码
2018/09/20 jQuery
AJAX在JQuery中的应用详解
2019/01/30 jQuery
详解JavaScript函数callee、call、apply的区别
2019/03/08 Javascript
js实现div色块碰撞
2020/01/16 Javascript
在Python中使用SimpleParse模块进行解析的教程
2015/04/11 Python
Python自动化开发学习之三级菜单制作
2017/07/14 Python
python实现连续图文识别
2018/12/18 Python
Python实现银行账户资金交易管理系统
2020/01/03 Python
python开发实例之Python的Twisted框架中Deferred对象的详细用法与实例
2020/03/19 Python
Python requests模块session代码实例
2020/04/14 Python
基于Python爬取股票数据过程详解
2020/10/21 Python
python3列表删除大量重复元素remove()方法的问题详解
2021/01/04 Python
韩国知名的家庭购物网站:CJmall
2016/08/01 全球购物
Osklen官方在线商店:巴西服装品牌
2019/04/25 全球购物
节约用水的口号
2014/06/20 职场文书
优秀班主任事迹材料
2014/12/16 职场文书
担保贷款承诺书
2015/04/30 职场文书
学校通报表扬范文
2015/05/04 职场文书
pandas中DataFrame重置索引的几种方法
2021/05/24 Python