ES6+ 开发 React 组件

在这里简要的说一下这些语言新特性对 React 应用的开发有什么影响,这些 ES6+ 特性使得 React 开发更简单更有趣。

迄今为止,最能体现我们使用 ES6+ 来编写 React 组件的就是我们选择使用类定义语法。替代了使用 React.createClass 方法来定义一个组件,我们可以定义一个 bonafide ES6 类来扩展 React.Component:

1 2 3 4 5

class Photo extends React.Component {   render() {     return <img alt={this.props.caption} src={this.props.src} />;   } }

现在,你就会发现一个微妙的差异 —— 当使用定义类的时候语法更简洁:

1 2 3 4 5

// The ES5 way var Photo = React.createClass({   handleDoubleTap: function(e) { … },   render: function() { … }, });

1 2 3 4 5

// The ES6+ way class Photo extends React.Component {   handleDoubleTap(e) { … }   render() { … } }

值得关注的是,我们去掉了两个括号和一个分号,每个方法声明我们省略了一个冒号,一个关键字和一个分号。

当使用新的类定义时,所有的生命周期方法至少有一个是符合你期望的。类的 constructor 现在假设 role 之前是通过 componentWillMount 填充的:

1 2 3 4

// The ES5 way var EmbedModal = React.createClass({   componentWillMount: function() { … }, });

1 2 3 4 5 6 7

// The ES6+ way class EmbedModal extends React.Component {   constructor(props) {     super(props);     // Operations usually carried out in componentWillMount go here   } }

属性初始化程序

在 ES6+ 类的世界里,prop types 和 defaults live 在类自身作为静态属性。这些,在组件的初始化状态也是一样的,可以使用 ES7 property initializers 定义:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

// The ES5 way var Video = React.createClass({   getDefaultProps: function() {     return {       autoPlay: false,       maxLoops: 10,     };   },   getInitialState: function() {     return {       loopsRemaining: this.props.maxLoops,     };   },   propTypes: {     autoPlay: React.PropTypes.bool.isRequired,     maxLoops: React.PropTypes.number.isRequired,     posterFrameSrc: React.PropTypes.string.isRequired,     videoSrc: React.PropTypes.string.isRequired,   }, });

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

// The ES6+ way class Video extends React.Component {   static defaultProps = {     autoPlay: false,     maxLoops: 10,   }   static propTypes = {     autoPlay: React.PropTypes.bool.isRequired,     maxLoops: React.PropTypes.number.isRequired,     posterFrameSrc: React.PropTypes.string.isRequired,     videoSrc: React.PropTypes.string.isRequired,   }   state = {     loopsRemaining: this.props.maxLoops,   } }

ES7 属性初始化程序操作内部类的 constructor,this 指向 construction 的类实例,所以初始化状态可以依赖于 this.props。值得关注的是,我们不再定义 prop 默认值和使用 getter 函数初始化状态对象。

Arrow 函数

React.createClass 方法用来在你的组件实例方法中执行一些额外的绑定工作,为了确保 this 关键字会指向组件实例: 

1 2 3 4 5 6 7

// Autobinding, brought to you by React.createClass var PostInfo = React.createClass({   handleOptionsButtonClick: function(e) {     // Here, 'this' refers to the component instance.     this.setState({showOptionsModal: true});   }, });

自从我们不参与 React.createClass 方法,而是使用 ES6+ 类语法定义组件,看似需要手动绑定实例方法:

1 2 3 4 5 6 7 8 9 10 11 12

// Manually bind, wherever you need to class PostInfo extends React.Component {   constructor(props) {     super(props);     // Manually bind this method to the component instance...     this.handleOptionsButtonClick = this.handleOptionsButtonClick.bind(this);   }   handleOptionsButtonClick(e) {     // ...to ensure that 'this' refers to the component instance here.     this.setState({showOptionsModal: true});   } }

幸运的是,通过绑定两个 ES6+ 特性 – arrow functions 和属性初始化程序  – 可以选择绑定组件实例:

1 2 3 4 5

class PostInfo extends React.Component {   handleOptionsButtonClick = (e) => {     this.setState({showOptionsModal: true});   } }

ES6 的 arrow 函数体分享相同的词  this,用这来围绕他们的代码,这些可以达到我们预期的结果,也是 ES7 属性初始化程序在域内的方式。 Peek under the hood 来看看为什么能实现。

动态属性名称 & 模板字符串

其中一个对象常量增强是可以分配到一个派生属性名称。我们最初可能会像下面这样设置一些状态:

1 2 3 4 5 6 7

var Form = React.createClass({   onChange: function(inputName, e) {     var stateToSet = {};     stateToSet[inputName + 'Value'] = e.target.value;     this.setState(stateToSet);   }, });

现在,我们有能力构造通过一个运行时 JavaScript 表达式确定属性名称的对象。这里,我们使用了一个模板字符串来确定哪个属性设置状态:

1 2 3 4 5 6 7

class Form extends React.Component {   onChange(inputName, e) {     this.setState({       [`${inputName}Value`]: e.target.value,     });   } }

解构 & 传播属性

通常在编写组件的时候,我们可能想把大部分父组件的 props 传递给子组件,但不是所有。结合 ES6+ 解构和 JSX 传播属性,这个不需要多余的部分就能实现:

1 2 3 4 5 6 7 8 9 10 11 12 13 14

class AutoloadingPostsGrid extends React.Component {   render() {     var {       className,       ...others,  // contains all properties of this.props except for className     } = this.props;     return (       <div className={className}>         <PostsGrid {...others} />         <button onClick={this.handleLoadMoreClick}>Load more</button>       </div>     );   } }

我们可以结合 JSX 传播属性和常规属性,利用一个简单的优先原则实现 overrides 和 defaults。这个元素会要求 className “override” 甚至是在 this.props 存在 className 属性: 

1 2 3

<div {...this.props} className="override">    …  </div>

这个元素常规来说需要 className “base” ,除非 this.props 有 className 属性覆盖: 

1 2 3

<div className="base" {...this.props}>    …  </div>

希望大家能享受 ES6+ 语言特性给 React 开发带来的一些便利。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏何俊林

自定义 Behavior - 仿新浪微博发现页的实现

图:四川九寨沟 本文来自徐俊的独家投稿,徐俊的blog地址为:博客地址:http://blog.csdn.net/gdutxiaoxu/,点击【阅读原文】,可查...

31810
来自专栏jianhuicode

仿腾讯课堂固定滚动列表ReactNative组件

前言 由于业务需要做成类似腾讯课堂课程详情滚动的效果,考虑到后面有可能有新的呈现方式,RN提供的组件没有这种滚动控件,不如自己封装,其实去年已经写了一篇但是写的...

5427
来自专栏blackheart的专栏

1.[Andriod]之Andriod布局 VS WinPhone布局

0.写在前面的话 近来被HTML+CSS的布局折腾的死去活来,眼巴巴的看着CSS3中的flex,grid等更便捷更高效的的布局方式无法在项目中应用,心里那叫一个...

1998
来自专栏xx_Cc的学习总结专栏

六天完成一个简单iOS App - 第五天

2736
来自专栏Sorrower的专栏

Android弹窗二则: PopupWindow和AlertDialog

android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app....

805
来自专栏非著名程序员

Android Material Design系列之RecyclerView和CardView

去年很早之前,我就讲解过RecyclerView的使用,今天我们就在讲解CardView的时候,顺便再把RecyclerView同时讲解一下。RecyclerV...

1818
来自专栏程序员宝库

分享前端开发常用代码片段

如果你的网页中需要使用大量初始不可见的(例如,悬停的)图像,那么可以预加载这些图像。

1065
来自专栏Android 开发者

用 CoordinatorLayout 处理滚动

2477
来自专栏青蛙要fly的专栏

项目需求讨论- 自定义滚轮(第二波新实现)

大家好,在前段时间我写过用ScrollView实现了自定义滚轮,但是在循环的效果不是特别好。(这次文章底部附上了Demo。O(∩_∩)O~)

732
来自专栏向治洪

React Native之TextInput组件实现联想输入

TextInput组件是最基本的组件,相关介绍请查看TextInput组件介绍 输入框组件属性 输入框组件的主要属性如下: autoCapitalize : ...

17710

扫描关注云+社区