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的。