React 专注于 view 层,组件化则是 React 的基础,也是其核心理念之一,一个完整的应用将由一个个独立的组件拼装而成。

  • 1. ES5写法React.createClass,
  • 2 . ES6写法React.Component,
  • 3. 无状态的函数式写法(纯组件-SFC)。

你们最钟爱哪种写法呢?萝卜青菜各有所爱~ 每个团队都有自己的代码规范和开发模式,但书写 React 组件时 都会以提高代码阅读性更优的组件性能易于 bug 追踪为原则。下面我们就聊聊这三种写法的区别,以及各自所适用场景的最佳实践。

ES5-写法 React.createClass(不推荐)

React.createClass不用多说,我们最早使用这个方法来构建一个组件“类”,它接受一个对象为参数,对象中必须声明一个render方法,render返回一个组件实例,下面用一个 SwitchButton 组件的例子来看看React.createClass的具体用法:

var React = require('react');
var ReactDOM = require('react-dom');var SwitchButton = React.createClass({getDefaultProp:function() {return { open: false }},getInitialState: function() {return { open: this.props.open };},handleClick: function(event) {this.setState({ open: !this.state.open });},render: function() {var open = this.state.open,className = open ? 'switch-button open' : 'btn-switch';return (<label className={className} onClick={this.handleClick.bind(this)}><input type="checkbox" checked={open}/></label>);}
});ReactDOM.render(<SwitchButton />,document.getElementById('app')
);

ES6-写法 React.Component(有状态组件可以用)

React 升级后就支持了 ES6 的class语法,我们可以使用class App extends React.Component{...}的方式创建组件,这也是目前官方推荐创建有状态组件的方式。用 ES6 重写上面 SwitchButton 组件的例子:

import React from 'react'
import { render } from 'react-dom'class SwitchButton extends React.Component {constructor(props) {super(props)// 设置 initial statethis.state = {open: this.props.open}this.handleClick = this.handleClick.bind(this)}handleClick(event) {this.setState({ open: !this.state.open })}render() {let open = this.state.open,className = open ? 'switch-button open' : 'btn-switch'return (<label className={className} onClick={this.handleClick}><input type="checkbox" checked={open}/></label>)}
}SwitchButton.defaultProps = {open: false
}render(<SwitchButton />,document.getElementById('app')
)

与React.createClass创建组件的不同之处:

1. import
与这里使用了 ES6 的import语句替代require()方法导入模块,其中import {render}可以直接从模块中导入变量名,这种写法更加简洁直观。

2. 初始化 state
React 使用 ES6 的“类”继承实现时,去掉了getInitialState这个 hook 函数,state的初始化放在构造函数方法constructor中声明。

3. this 绑定
React.createClass会自绑定函数方法(不像React.Component只绑定需要关心的函数)导致不必要的性能开销,增加代码过时的可能性。
React.Component创建组件时,事件函数并不会自动绑定this,需要我们手动绑定,不然this将不会指向当前组件的实例对象。以下有三种绑定this的方法:

(1). 在constructor中使用bind()进行硬绑定

constructor() {this.handleClick = this.handleClick.bind(this);
}

(2.) 直接在元素上使用bind()绑定

<label className={className} onClick={this.handleClick.bind(this)}>

(3). ES6 的 =>:Arrow Function(箭头函数)
它可以很方便的使this直接指向class SwitchButton(它的作用等同于大家熟悉的var self = this,但后者会让代码变得混乱,Arrow Function 就很好的解决了这一问题)

<label className={className} onClick={()=>this.handleClick()}>

(4)默认属性和状态不同
组件属性类型propTypes及其默认props属性defaultProps配置不同

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

const TodoItem = React.createClass({propTypes: { // as an objectname: React.PropTypes.string},getDefaultProps(){   // return a objectreturn {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 objectgetInitialState(){ return {isEditing: false}}render(){return <div></div>}
})
class TodoItem extends React.Component{constructor(props){super(props);this.state = { // define this.state in constructorisEditing: false} }render(){return <div></div>}
}

无状态的函数式写法(纯组件 SFC,推荐)

React.createClassReact.Component都可以用来创建有状态的组件,而 无状态组件 - Stateless Component 是 React 在 v0.14 之后推出的。

它的出现 是因为随着应用复杂度不断提升和组件本数量的增加,组件按各自职责被分成不同的类型,于是有一种只负责展示的纯组件出现了,它的特点是不需要管理状态state,数据直接通过props传入,这也符合 React 单向数据流的思想。

对于这种无状态的组件,使用函数式的方式声明,会使得代码的可读性更好,并能大大减少代码量,Arrow Function 则是函数式写法的最佳搭档:

const Todo = (props) => (<li
    onClick={props.onClick}style={{textDecoration: props.complete ? "line-through" : "none"}}>{props.text}</li>
)

上面定义的 Todo 组件,输入输出数据完全由props决定,而且不会产生任何副作用。对于props为 Object 类型时,我们还可以使用 ES6 的解构赋值:

const Todo = ({ onClick, complete, text, ...props }) => (<li
    onClick={onClick}style={{textDecoration: complete ? "line-through" : "none"}}{...props}>{props.text}</li>
)

无状态组件一般会搭配高阶组件(简称:OHC)一起使用,高阶组件用来托管state,Redux 框架就是通过 store 管理数据源和所有状态,其中所有负责展示的组件都使用无状态函数式的写法。

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

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

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

  • 组件不能访问this对象

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

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

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

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

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

当然,无状态组件也不是万金油,比如它不支持"ref",原因很简单,因为 React 调用它之前,组件不会被实例化,自然也就没有"ref",(reffindDOMNode实际上打破了父子组件之间仅通过 props 来传递状态的约定,违背了 React 的原则,需要避免)。

以上三种写法的比较,以及最佳实践

  • Facebook 官方早就声明 ES6React.Component将取代React.createClass。随着 React 不断发展,React.createClass暴露出一些问题:

  • 相比React.Component可以有选择性的绑定需要的函数,React.createClass会自动绑定函数,这样会导致不必要的性能开销。

  • React.createClass亲生的 mixin,React.Component不再支持,事实上 mixin 不够优雅直观,替代方案是使用更流行的高阶组件-HOC,如果你的项目还离不开 也可以使用 react-mixin

  • 总的来说:无状态函数式写法 优于React.createClass,而React.createClass优于React.Component。

参考资料:
创建 React 组件的三种方式 及最佳实践

React 组件的三种写法总结相关推荐

  1. vue单文件props写法_详解Vue 单文件组件的三种写法

    详解Vue 单文件组件的三种写法 JS构造选项写法 export defaul { data, methods, ...} JS class写法 @Component export default c ...

  2. react如何获取option的下标和值_select选中获取索引三种写法

    $('#someId').prop('selectedIndex'); $('option:selected', '#someId').index(); $('#someId option').ind ...

  3. 深入解析React创建组件的三种方式

    eact创建组件的三种方式: 1.函数式无状态组件 2.es5方式React.createClass组件 3.es6方式extends React.Component 三种创建方式的异同 1.函数式无 ...

  4. React类组件的两种写法

    react中类组件的两种写法: 要点:•类组件必须要继承React.Component •类组件中的render()方法,返回值是一个jsx // 方式一: import React from 're ...

  5. Vue——05-02组件的数据、为什么data要使用函数、父组件给子组件传递数据的三种写法、父传子以及传两种以上的值、默认值以及父传子的引用类型

    目录 在组件中获取数据 二.组件中的data为什么必须要是函数? 父组件给子组件传递数据--props属性 第一种写法: 第二种写法: 第三种写法: 传默认值 : 父组件传子组件数据--引用类型的两种 ...

  6. react的ref三种使用方式,获取元素内容

    react的ref三种使用方式,获取元素内容. 注意:应尽可能少的使用ref,优先使用state 1.字符串 refGetData1=()=>{alert("获取到的内容:" ...

  7. 如何从零开始创建React项目(三种方式)

    在开发 React 项目前最关键的当然是项目的创建,现在的前端工程化使得前端项目的创建也变得越来越复杂,在这里介绍三种从零开始创建 React 项目的方式,分别是 "在浏览器中直接引入&qu ...

  8. CSS伪类的三种写法

    今天逛蓝色时,无意发现了有人讨论伪类的正确写法,让我对伪类的认识也更清晰了,转贴于此,以备日后查询(原贴当时没记下地址,已经记不得了) Code <style> a.tb{text-dec ...

  9. Promise的链式调用三种写法,Promise.all与式调用

    Promise的链式调用三种写法: // 1,Promise原始链式调用 new Promise((resolve, reject) => {setTimeout(() => {conso ...

  10. android 闪屏页处理_Android应用闪屏页延迟跳转的三种写法

    闪屏页也称之为欢迎页.在打开一个App时,我们第一眼看到的往往是一个闪屏页面,之所以叫闪屏页,是因为它出现之后会短暂地停留几秒钟再跳转到其他页面.闪屏页除了使用户体验更好外,还能给app留出初始化数据 ...

最新文章

  1. 邮件服务器轻松组建 友旺MG1200功能介绍
  2. 软件项目管理0703:净收确认
  3. 算法设计与分析——算法思想总结
  4. 南海发展大数据产业 建设新型智慧城市
  5. java实践体会,java实践心得体会范文3篇
  6. 神州数码:我国市民卡发展之路探讨
  7. 已解决-MacBook pro/MacBook air上安装Windows10双系统教程
  8. 转-零死角玩转stm32-高级篇之SDIO(4bit + DMA、支持SDHC、带协议分析)
  9. Yuga Labs大举扩张,“猿”宇宙已经不远了?
  10. 密码爆破工具——九头蛇(hydra)
  11. 7-11 群发邮件 (10 分)
  12. 数据结构PTA 基础实验7-2.1 魔法优惠券
  13. 前端第二章:3.HTML文档声明、存储容量换算、字符编码、字符集、HTML帮助文档Zeal
  14. FFmpeg[32] - x264 [error]: high422 profile doesn‘t support lossless
  15. 欺骗的艺术——第二部分(2)
  16. python调用海康威视工业相机SDK实现图片采集
  17. 树莓派远程视频监控的移植pistreaming
  18. 惠普服务器SPP包制作方法
  19. 163邮箱如何申请注册个人?163电子邮箱个人怎么注册?
  20. 【通信原理 入坑之路】——信息论部分 之 离散无记忆信源的等长编码

热门文章

  1. 唯心主义-柏拉图的哲学世界
  2. ZZM区块链全球区块文化娱乐相结合的新型网站源码
  3. PR基础学习(二) 导入和预览素材视频
  4. 良心推荐7个实用网站
  5. 最实用的上网网址一览表
  6. 天下网商属于阿里系吗_“阿里公子”商标申请被驳回,不属于马云父亲的阿里家族吗?...
  7. 【TypeScript】使用CRA创建支持TS的React项目(从踩坑到放弃)
  8. 全网目前最全python例子
  9. 视频画面怎么快速进行水平翻转?
  10. 国内超强JS框架正在开源免费申请中