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

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形式创建组件

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

(0)

相关推荐

  • 使用React实现轮播效果组件示例代码

    前言 我发现React和AngularJS思想完全不同,AngularJS是基于双向绑定,在Modal层中定制数据,然后双向改变.但是React是通过prop和state来改变view层的状态.下面是我写的一个轮播图组件,可以直接看一下.代码很简单.原理就是通过React在componentDidMount后改变setState,来动态改变css样式. 说明以下:看gif很卡,但是实际效果还是很好的. 以下是示例代码 LunBo.js require('styles/App.css'); req

  • React如何利用相对于根目录进行引用组件详解

    前言 本文主要给大家介绍了关于React利用相对于根目录进行引用组件的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 在对自己开发的组件中经常会做诸如以下的引用: import genFetchEntryListArgs from '../../../utils/table/genFetchEntryListArgs'; import { parseQuery, stringifyQuery } from '../../../utils/query'; import

  • React组件之间的通信的实例代码

    最近学习浅尝则止的学习了一下react.js这个UI的框架,react这个库给我的最大的感觉就是它能够完全的接管UI层,在要改变视图的东西的时候只需要改变其this.state中的状态.只要操作数据层的东西视图层就会发生变化,这一点我还是很喜欢的.可以摆脱对DOM的直接操作,毕竟直接来会比较复杂,本来应该是逻辑层js中混杂着各种css的字符串,对于我来说有点不爽(JSX中也混杂这标签,但我觉的不应该把它看作标签,看作语句会习惯一点). 回到几天的重点,讲react组件之间的状态传递. 上代码:

  • React组件生命周期详解

    调用流程可以参看上图. React组件提供了生命周期的钩子函数去响应组件不同时刻的状态,组件的生命周期如下: 实例化 存在期 销毁期 实例化 首次调用组件时,有以下方法会被调用(注意顺序,从上到下先后执行): getDefaultProps 这个方法是用来设置组件默认的props,组件生命周期只会调用一次.但是只适合react.createClass直接创建的组件,使用ES6/ES7创建的这个方法不可使用,ES6/ES7可以使用下面方式: //es7 class Component { stat

  • React组件的三种写法总结

    React 专注于 view 层,组件化则是 React 的基础,也是其核心理念之一,一个完整的应用将由一个个独立的组件拼装而成. 截至目前 React 已经更新到 v15.4.2,由于 ES6 的普及和不同业务场景的影响,我们会发现目前主要有三种创建 React 组件的写法:1. ES5写法React.createClass,2. ES6写法React.Component,3. 无状态的函数式写法(纯组件-SFC). 你们最钟爱哪种写法呢?萝卜青菜各有所爱~ 每个团队都有自己的代码规范和开发模

  • 详解React中的组件通信问题

    引入 本来我是没想过总结这些东西的,会感觉比较入门.但是之前同学去腾讯面试问到了这个问题(react或vue的组件通信),我帮他整理,顺便写demo的过程中,会有一些新的体会,多总结还是有利于进步的呀. 父子组件 父 → 子 parent组件传给child组件,符合react的单向数据流理念,自上到下传递props. // 父组件 class Parent extends Component { constructor() { super(); this.state = { value: '',

  • React进阶学习之组件的解耦之道

    前言 众所周知,React中的组件非常的灵活可扩展,不过随着业务复杂度的增加和许多外部工具库的引入,组件往往也会显得浮肿,接下来我们就一起来看看常见的几种,遵循单一职责原则的,组件分割与解耦的方法,话不多说了,来一起看看详细的介绍: 一.分割 render 函数 当一个组件渲染的内容较多时,有一个快速并且通用的方法是创建sub-render函数来简化原来庞大的 render class Panel extends React.Component { renderHeading() { // ..

  • 基于react组件之间的参数传递(详解)

    1.父组件向子组件传递参数 class Child extends Component { componentDidMount(){ let name = this.props.default; console,log(name); } render(){ const { default} = this.props; return ( <Input /> ) } } import React, { Component } from 'react'; import Child from './C

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

    React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归:具体的三种方式: 函数式定义的无状态组件 es5原生方式React.createClass定义的组件 es6形式的extends React.Component定义的组件 虽然有三种方式可以定义react的组件,那么这三种定义组件方式有什么不同呢?或者说为什么会出现对应的定义方式呢?下面就简单介绍一下. 无状态函数式组件 创建无状态函数式组件形式是从React 0.14版本开始出现的.它是为了创建纯展示组件,这种组件

  • React构建组件的几种方式及区别

    目录 一.组件是什么 二.如何构建 函数式创建 通过 React.createClass 方法创建 继承 React.Component 创建 三.区别 一.组件是什么 组件就是把图形.非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式 在React中,一个类.一个函数都可以视为一个组件 组件所存在的优势: 降低整个系统的耦合度,在保持接口不变的情况下,我们可以替换不同的组件快速完成需求,例如输入框,可以替换为日历.时间.范围等组件作具体的实现 调试方便,由于整个系统是通过组件组合起

  • JS中创建函数的三种方式及区别

    1.函数声明 function sum1(n1,n2){ return n1+n2; }; 2.函数表达式,又叫函数字面量 var sum2=function(n1,n2){ return n1+n2; }; 两者的区别:解析器会先读取函数声明,并使其在执行任何代码之前可以访问:而函数表达式则必须等到解析器执行到它所在的代码行才会真正被解释执行. 自执行函数严格来说也叫函数表达式,它主要用于创建一个新的作用域,在此作用域内声明的变量,不会和其它作用域内的变量冲突或混淆,大多是以匿名函数方式存在,

  • Spring Boot 教程之创建项目的三种方式

    目录 一.前言 二.Spring Boot 简介 三.如何创建 Spring Boot 项目 在线创建 IntelliJ IDEA 创建 Maven 创建 四.常见项目结构 代码层 资源文件结构 五.@SpringBootApplication 注解分析 相关代码 说明 六.pom.xml 分析 七.总结 一.前言 如果你是一个浸淫 SpringBoot 已久的老手,那么可能下面的内容可能不那么适合你,写得很简单.但如果是 对于一个刚学习 SpringBoot 的新手而言,我想多少还是有些用的.

  • Spring框架通过工厂创建Bean的三种方式实现

    工厂模式 Spring中bean的创建,默认是框架利用反射new出来的bean实例.有时候也会有一些复杂的情况. 假设有一个飞机,属性如下,现在需要造很多同型号的飞机,那么唯一需要改变的属性只有DriverName(机长姓名),此时可以使用工厂模式帮我们创建对象,有一个专门帮我们创建对象的类帮我们创建对象,这个类就叫工厂. public class AirPlane { private String DriverName;// 机长姓名 private String AirPlaneName;/

  • javascript函数命名的三种方式及区别介绍

    javascript函数命名的三种方式及区别介绍 第一 复制代码 代码如下: function fn(val1,val2) { alert(val1+val2); } fn(1,2); 第二 复制代码 代码如下: var fn=function() { alert(val1+val2); } fn(1,2); 第三 复制代码 代码如下: var fn=new Function("alert(val1+val2)"); fn(1,2); 上面三种方式逻辑上是等价的,但是还是有点小区别:区

  • 判断python对象是否可调用的三种方式及其区别详解

    查找资料,基本上判断python对象是否为可调用的函数,有三种方法 使用内置的callable函数 callable(func) 用于检查对象是否可调用,返回True也可能调用失败,但是返回False一定不可调用. 官方文档:https://docs.python.org/3/library/functions.html?highlight=callable#callable 判断对象类型是否是FunctionType type(func) is FunctionType # 或者 isinst

  • 详谈js对url进行编码和解码(三种方式的区别)

    Javascript语言用于编码的函数,一共有三个,最古老的一个就是escape().虽然这个函数现在已经不提倡使用了,但是由于历史原因,很多地方还在使用它,所以有必要先从它讲起. escape 和 unescape 实际上,escape()不能直接用于URL编码,它的真正作用是返回一个字符的Unicode编码值.比如"春节"的返回结果是%u6625%u8282,也就是说在Unicode字符集中,"春"是第6625个(十六进制)字符,"节"是第8

  • JavaScript常用截取字符串的三种方式用法区别实例解析

    stringObject.substring(start,stop) 用于提取字符串中介于两个指定下标之间的字符. start必需.一个非负的整数,规定要提取的子串的第一个字符在 stringObject 中的位置. stop可选.一个非负的整数,比要提取的子串的最后一个字符在 stringObject 中的位置多 1.如果省略该参数,那么返回的子串会一直到字符串的结尾. start从0开始 到stop(不包含stop)结束 不接受负的参数. stringObject.substr(start,

  • Spring创建bean对象三种方式代码实例

    一.使用无参构造方法创建 二.使用静态工厂创建 三.使用实例工厂创建 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

随机推荐