React组件的三种写法总结


Posted in Javascript onJanuary 12, 2017

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

截至目前 React 已经更新到 v15.4.2,由于 ES6 的普及和不同业务场景的影响,我们会发现目前主要有三种创建 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 升级到 v0.13 后就支持了 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)
 this.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创建组件的不同之处:

import

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

初始化 state

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

this 绑定

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()}>

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

React.createClass和React.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 管理数据源和所有状态,其中所有负责展示的组件都使用无状态函数式的写法。

这种模式被鼓励在大型项目中尽可能以简单的写法 来分割原本庞大的组件,而未来 React 也会面向这种无状态的组件进行一些专门的优化,比如避免无意义的检查或内存分配。所以建议大家尽可能在项目中使用无状态组件。

当然,无状态组件也不是万金油,比如它不支持"ref",原因很简单,因为 React 调用它之前,组件不会被实例化,自然也就没有"ref",(ref和findDOMNode实际上打破了父子组件之间仅通过 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。

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

Javascript 相关文章推荐
javascript学习(二)javascript常见问题总结
Jan 02 Javascript
javascript实现一个简单的弹出窗
Feb 22 Javascript
JS+CSS实现鼠标经过弹出一个DIV框完整实例(带缓冲动画渐变效果)
Mar 25 Javascript
JavaScript的变量声明提升问题浅析(Hoisting)
Nov 30 Javascript
浅析webpack 如何优雅的使用tree-shaking(摇树优化)
Aug 16 Javascript
JavaScript实现HTML5游戏断线自动重连的方法
Sep 18 Javascript
vue2实现可复用的轮播图carousel组件详解
Nov 27 Javascript
Vue引入jquery实现平滑滚动到指定位置
May 09 jQuery
JavaScript引用类型Object常见用法实例分析
Aug 08 Javascript
laravel实现中文和英语互相切换的例子
Sep 30 Javascript
使用Mock.js生成前端测试数据
Dec 13 Javascript
原生JavaScript实现购物车
Jan 10 Javascript
JQuery异步提交表单与文件上传功能示例
Jan 12 #Javascript
jQuery命名空间与闭包用法示例
Jan 12 #Javascript
jquery实现百叶窗效果
Jan 12 #Javascript
基于JavaScript实现带缩略图的轮播效果
Jan 12 #Javascript
js通过指定下标或指定元素进行删除数组的实例
Jan 12 #Javascript
js仿搜狐视频记录片列表展示效果
May 30 #Javascript
原生js实现商品放大镜效果
Jan 12 #Javascript
You might like
WordPress判断用户是否登录的代码
2011/03/17 PHP
php取整函数ceil,floo,round的用法及介绍
2013/08/31 PHP
php过滤XSS攻击的函数
2013/11/12 PHP
PHP生成条形图的方法
2014/12/10 PHP
php获取微信基础接口凭证Access_token
2018/08/23 PHP
Laravel使用原生sql语句并调用的方法
2019/10/09 PHP
彪哥1.1(智能表格)提供下载
2006/09/07 Javascript
Js如何判断客户端是PC还是手持设备简单分析
2012/11/22 Javascript
jquery数组之存放checkbox全选值示例代码
2013/12/20 Javascript
js传值后台中文出现乱码的解决方法
2016/06/30 Javascript
第一次动手实现bootstrap table分页效果
2016/09/22 Javascript
Vue获取DOM元素样式和样式更改示例
2017/03/07 Javascript
5分钟快速掌握JS中var、let和const的异同
2018/09/19 Javascript
js中的深浅拷贝问题简析
2019/05/10 Javascript
Vue.js项目实战之多语种网站的功能实现(租车)
2019/08/07 Javascript
js中!和!!的区别与用法
2020/05/09 Javascript
vue实现编辑器键盘抬起时内容跟随光标距顶位置向上滚动效果
2020/05/28 Javascript
Python深入学习之闭包
2014/08/31 Python
用Python代码来解图片迷宫的方法整理
2015/04/02 Python
TF-IDF与余弦相似性的应用(二) 找出相似文章
2017/12/21 Python
Python简单实现控制电脑的方法
2018/01/22 Python
python文件读写代码实例
2019/10/21 Python
Tensorflow训练MNIST手写数字识别模型
2020/02/13 Python
Python二元算术运算常用方法解析
2020/09/15 Python
加大码胸罩、内裤和服装:Just My Size
2019/03/21 全球购物
如何通过jdbc调用存储过程
2012/04/19 面试题
个人简历自我鉴定
2013/10/11 职场文书
房地产销售经理岗位职责
2014/01/01 职场文书
中小学校园安全广播稿
2014/09/29 职场文书
学校食品安全责任书
2015/01/29 职场文书
5.12护士节活动总结
2015/02/10 职场文书
同学会感言
2015/07/30 职场文书
公司客户答谢酒会祝酒词
2015/08/11 职场文书
2019年汽车租赁合同范本!
2019/08/12 职场文书
python基础详解之if循环语句
2021/04/24 Python
详解TypeScript的基础类型
2022/02/18 Javascript