在这里简要的说一下这些语言新特性对 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 函数初始化状态对象。
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 开发带来的一些便利。