React.js是Facebook开发的框架。html
http://facebook.github.io/react/html5
官网上的描述是「A JavaScript library for building user interfaces」 React.js是用来构造UI的框架。不是一个framework,只是用来构造UI的library,提供MVC中View的机能。react
采用了它进行开发的天然有Facebook自己,Instagram、Yahoo、Airbnb等等,是当今备受瞩目的library。git
为了了解React.js的特征,先与其余library或framework相比较。好比像Todo MVC这样对框架进行选型,以发送表单为例子进行实装试验。github
单纯jQuery的写法:npm
1
2
3
4
5
6
7
8
9
|
// 点了Submit以后
$('form').on('submit', functino() {
// 建立dom元素
var $li = $('<li>');
// ...
// 追加到list
$('ul').append($li);
});
|
但是,这样被DOM的结构所限制,要追加什么功能都很是麻烦,测试case也很差写。babel
Backbone.js能够必定程度上解决相似问题。Backbone.js把管理数据的Model、与管理表现的View分开、而后把View分红各类组件来设计。好比下面这样:架构
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var FormView = Backbone.View.extend({
onSubmit: function() {
// 建立data后只要追加到model
this.collection.add(data)
}
});
var ListView = Backbone.View.extend({
initialize: function() {
// model更新后追加到list
this.collection.on('add', this.render);
}
});
|
对FormView或ListView来讲、都属于UI的一类功能、同类型的东西都只要调用组件就能够实现。mvc
Backbone.js把数据和组件分开管理之后就更容易管理,但View的更新还须要手动来写仍然很是麻烦,Model与View之间传递事件也变得复杂,代码量扩大的时候就会出现不少问题。(和Backbone.js相似的library好比Marionette和Chaplin、本质上问题是同样的)app
Angular.js、Vue.js为表明的、所谓MVVM系library的特征是数据一旦发生改变就会自动更新显示。
1
2
3
4
5
6
7
8
9
|
<form ng-submit="onSubmit()">
<input type="text" ng-model="text">
</form>
<ul>
<li ng-repeat="item in list">
{{item.text}}
</li>
</ul>
|
1
2
3
4
5
|
// Controller
$scope.onSubmit = function() {
// data更新后自动就显示了
$scope.list.push(newItem);
};
|
这样记录了HTML中用到的数据、JavaScript就自动把数据更新上去显示了。可是,这种类型的library在规模变大的时候要管理状态是很难的。
jQuery也好Backbone.js、Angular.js也罢,上面说了都不适应管理大规模的代码。虽然严谨的设计仍然能够成就方便管理的应用。可是,就违背了开发这些框架的本意,代码变得臃肿,设计也不简单。
React.js是规模再大也能提供便利管理的library。相反的,开发高速的小型应用Backbone.js或者Vue.js就更为合适。
React.js的特征是尽可能作到组件无状态,便利的对组件进行管理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var Form = React.createClass({
onSubmit: function() {
// 通知父级数据有更新
},
render: function() {
return <form onSubmit={this.onSubmit}>...</form>;
}
});
var List = React.createClass({
render: function() {
// 从父级拿到数据进行更新
return <ul>{this.props.list.map(...)</ul>;
}
});
|
各组件都从父级拿数据而后再去建立View。这一点很重要,组件自身不须要维持状态。一般根据从外部获得的输入进行输出或者测试的状况(大多数状况来自父级组件),管理和复用性都很高。
固然,所有组件都不维持状态的话与静态的HTML并没有二致,有一些组件仍是须要保持状态的。让尽可能少的组件来维持状态,就是设计React.js的初衷。
一般是根节点组件在维持状态,它的子节点组件来传递:
然而,组件的状态一旦改变就会自动刷新树的结构,不须要手动操做,这与Angular.js之类是同样的。
数据一旦改变就自动显示的考虑也相同。
大部分根节点之外的组件都不用保持状态,用户的输入随着用户操做改变的话是须要维持自身的状态。
根节点组件保持了状态,它的状态一改变就刷新DOM树的设计很是单纯,一部分的改变致使整个DOM树的刷新影响性能。
这样React.js就引入了Virtual DOM的概念。
Virtual DOM粗略的说,就是构成DOM树的JavaScript对象、计算须要更新数据的对象后再实际更新最少须要更新的DOM元素。
React.js是用React.createClass
建立组件,用render方法的返回值获得Virtual DOM。Virtual DOM是React.createElement建立而
成的。
1
2
3
4
5
6
7
8
|
var MyComponent = React.createClass({
render: function() {
return React.createElement("div", {className: "foo"},
React.createElement("div", {className: "bar"},
"Hello ", this.props.name
)
);
});
|
并且,JSX使用独特的语法,用XML相似的语法来表现Virtual DOM。
1
2
3
4
5
6
7
8
9
10
11
|
var MyComponent = React.createClass({
render: function() {
return (
<div className="foo">
<div className="bar">
Hello {this.props.name}
</div>
</div>
);
}
});
|
用react-tools和babel这样的tool能够直接转换成JavaScript。
有人以为React.js速度很快,但真的是这样吗?采用了Virtual DOM之后,即使要更新根节点的数据也能最小限度的刷新DOM,确实应该是很快的,比刷新整个DOM树是要快不少。分三种状况进行性能测定:
结果以下图所示:
这样的话,React.js、Backbone.js只刷新部分DOM树明显是比刷新整个DOM树要快不少的。
如上所述,只让根节点保持状态是很是简单的设计,在这种简单设计的前提下一样提供比较好的性能,是React.js最大的特色。
Flux是Facebook很是提倡的一种应用架构设计。常常被拿来和MVC做比较、与MVC不一样的是它的数据只有一个流向。
至此为止、做为React.js的设计理念、由根节点保持状态,一旦什么发生改变就刷新那个状态,无论怎样的变动都通知刷新,却不会知道具体是怎样的变动。
例如,DOM树的末端组件检测到用户的操做,须要刷新根节点的状态。这个时候,React.js中这个末端组件是无状态的,必需要马上经过事件传递通知父级组件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
var Parent = React.createClass({
handleChange: function(changedData) {
// 子元素有什么须要更新的时候
},
render: function() {
// 设定子元素的事件处理函数
return <Child onChange={this.handleChange}>a</Child>;
}
});
var Child = React.createClass({
handleSubmit: function() {
// 父元素接收到事件进行处理
this.props.onChange(changedData);
},
render: function() {
// 设定表单的事件处理函数
return <form onSubmit={this.handleSubmit}>...</form>;
}
});
|
然而、用这种方法在嵌套较深的状况下更新组件时要传递给用来保持状态的根组件就很是的麻烦。那样,Flux中由View引发的变动进入Action(行为)而后经过Dispatcher(调度)以后Store(存储)后才能完成状态更新。
所谓Store是对数据的管理,至关于MVC模型中的M。View的根节点组件会读取Store中的变化,Store会自动更新数据。
Flux自己的设计理念是如此,实际应用却形形色色。Flux的原始设计是Facebook作的facebook/flux。是最小限度采用Dispacher的例子,其余实例还有以下一些:
上文说明了React.js和Flux的设计思想和特征。React.js适用于有扩展需求的大型项目,却不适合敏捷开发小型应用。那样的需求采用Angular.js或者Vue.js的更多。静态的页面中少量UI单纯用jQuery也很便利。
实际上用过React.js和Flux写过应用就知道,组件要对应状态是一件很麻烦的事。然而,用这些麻烦的代价换来的是具备更强稳定性、更易维护的应用。
若是有这样的需求,仍是值得考虑采用React.js的。