原文連接:http://mp.weixin.qq.com/s?__biz=MzA5Njc3Njk5NA==&mid=2650528748&idx=1&sn=4d3093e963ce76c642eb0c5d9a97625b#rd前端
React來自於Facebook,是的,就是那個大家據說過可是打不開的網站。Facebook的開發者當時在開發一個廣告系統,由於對當前全部的MVC框架不滿意,因此就本身寫了一個UI框架,因而就有了React。後來由於以爲實在是好用,因此在2013年月份開源的此框架。通過這幾年的沉澱,React愈來愈強大,也受到了愈來愈多的開發者喜好。React目前(2015-05-04)的版本是0.14.0,從版本號上看尚未達到1.0版,意味着React還在頻繁地修改,廣泛應用於產品中還須要必定的時間。2015年三月份的F8開發者大會上,Facebook又發佈了React Native,正式把React的觸角伸向了APP。同時還爲React native開發了一款基於Atom的IDE-Nuclide,也是開源。react
React來勢洶洶,大有一統江湖的氣勢。前端開發者應該保持學習新技術的熱情,頗有必要熟悉React相關技術。下面咱們簡要談談React相關的技術。git
熟悉一個新技術的關鍵是熟悉他的特點和理念github
React框架自己和咱們經常使用的JavaScript MVC框架,如:AngularJS,Backbone,Ember等,沒有直接的可比性。在React的官方博客中明確闡述了React不是一個MVC框架,而是一個用於構建組件化UI的庫,是一個前端界面開發工具。因此頂多算是MVC中的V(view)。React並無重複造輪子,而是有不少顛覆性的創新,具體的特性以下:瀏覽器
在年初的React開發者大會上,React的項目經理Tom Occhino講述了React的最大的價值,React最大的價值不是高性能的虛擬DOM、封裝的事件機制、服務器端渲染,而是聲明式的直觀的編碼方式。React號稱能讓新人第一天開始使用就能開發新功能。簡單的編碼方式會讓新手能很快地上手,同時也下降了代碼維護的成本。這一特性決定了React能快速引發開發者的興趣並普遍傳播的基礎。如下是React基於這一理念的具體作法。服務器
React構建UI是使用組件化的方式,而不是常見的模板。組件並非一個新概念,它是某個獨立功能或者界面的封裝,達到複用或者UI和業務鬆耦合的目的。架構
組件化的設計理念也出現了不少年了,咱們經常使用的ExtJS、YUI、jQueryUI、BootStrap等等都會提供大量的可複用的UI組件。好比在Bootstrap中使用對話框組件:app
// 初始化 $('#myModal').modal({ keyboard: false }); // 顯示 $('#myModal').modal('show'); // 關閉事件 $('#myModal').on('hidden.bs.modal', function (e) { // do something... });
能夠看到咱們經常使用的這些組件提供了大量的接口和配置,讓開發者選擇合適的使用場景。這些組件的設計複雜,使用也較繁瑣,新人上手有必定的門檻。W3C也在加緊制定Web Components(即組件)的標準,試圖制定一個統一的簡單實用的標準化的組件概念。咱們看看React是如何設計組件模型的以及其和Web Component的區別。框架
React框架裏面使用了簡化的組件模型,但更完全地使用了組件化的概念。React將整個UI上的每個功能模塊定義成組件,而後將小的組件經過組合或者嵌套的方式構成更大的組件。這種作法已經在instagram網站上廣泛實施,你們能夠看看instagram的前端源代碼。 以下經過一個簡單的例子來闡述React中模塊化的概念。這個例子來自於React的官方網站教程,是完成一個簡單的評論框。這個評論框主要包含兩個部分,評論列表和評論表單。顯示效果以下:ide
按照React模塊組合的設計,把評論框組件commentBox分爲兩個子組件模塊:commentList和commentForm,代碼以下:
<div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div>
commentList和commentForm組件對應的代碼以下:
<div className="commentList"> {commentNodes} </div> <form className="commentForm" onSubmit={this.handleSubmit}> <input type="text" placeholder="Your name" ref="author" /> <input type="text" placeholder="Say something..." ref="text" /> <input type="submit" value="Post" /> </form>
從代碼中能夠看到CommentList組件又能夠劃分爲comment組件的列表。comment組件代碼以下:
<div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML= /> </div>
能夠看出,爲了完成評論框功能,使用React定義了四個不一樣的組件:commentBox、commentList、commentForm、comment。commentBox是由commentList和commentForm組合而來,commentList是由comment組合而來。這個例子充分體現了React組件化的理念,每一個組件的UI和邏輯都定義到了內部,暴露少許的API和外部交互,組件之間組合造成更復雜的組件。總結一下,React的組件具備以下的特性:
可組合:簡單組件能夠組合爲複雜的組件
可重用:每一個組件都是獨立的,能夠被多個組件使用
可維護:和組件相關的邏輯和UI都封裝在了組件的內部,方便維護
可測試:由於組件的獨立性,測試組件就變得方便不少。
React使用了組件化的設計,因此開發者天然而然和原生的Web Components相提並論,StackExchange上有一篇精彩的討論,解釋了React的組件和原生組件的對比。文章從語言層面、樣式的封裝、數據綁定、DOM操做方式等這幾個方面展開討論,結論是說二者沒有優劣之分,只是編碼習慣問題。Web Components規範畢竟還在制定過程當中,應該能夠從React的組件設計方式上借鑑一些理念。在後續的文章中,會深刻探討React中組件的設計原理及使用。
在JavaScript中DOM操做是獨立成爲一個分支的。各瀏覽器在實現DOM操做庫也是大同小異,都是在單獨的模塊中實現了DOM操做,因爲各類技術上的緣由,DOM操做的性能損耗相對於其餘操做是很大的。在前端開發中都是須要特別儘可能保持較小的DOM操做次數來提升性能。
React做爲一個UI框架,不可避免要有界面上元素的交互。爲了提升性能,React在操做頁面交互時引入了虛擬DOM的概念。虛擬DOM是在React中用JavaScript從新實現的一個DOM模型,和原生的DOM並無多少關係,只是借鑑了原生DOM的一些概念。虛擬DOM並無徹底實現DOM,只是保留了元素直接的層級關係和少許必要的屬性。由於減小了沒必要要的複雜性,實踐校驗的結果是虛擬DOM的性能比原生DOM高不少。來看看普通DOM和虛擬DOM在代碼上的差異。
以下是使用原生DOM生成的元素:
var a = document.createElement('a') a.setAttribute('class', 'link') a.setAttribute('href', 'https://github.com/facebook/react') a.appendChild(document.createTextNode('React'))
那麼使用虛擬DOM則代碼爲以下:
var a = React.createElement('a', { className: 'link', href: 'https://github.com/facebook/react' }, 'React')
能夠看到React中使用了本身實現的createElement
方法來生成元素DOM結構。
基於React開發中構建的DOM都是經過虛擬DOM進行的。在React的實際的使用中,須要根據不一樣的數據展示不一樣的UI,當數據變化時,React會從新構建整個DOM樹,而後將當前的DOM樹和以前的比較,獲得DOM樹的區別,而後僅僅把變化的部分反映到實際的瀏覽器UI更新上。React會在同一個事件循環內合併DOM的變化,只是會對比開始和結束的DOM變化,忽略中間過程的DOM變化。儘管每次數據變化都是從新構建DOM樹,但虛擬DOM的操做性能極高。這樣使用React時,開發者不在須要關心數據變化時頁面上DOM元素的更新,而只是關心各個數據狀態下頁面實際展示的效果。此外,由於React使用了由JavaScript實現的虛擬DOM,意味着能夠在服務器端完成HTML結構的構建。
JSX是React的重要組成部分,他使用相似XML標記的方式來聲明界面及關係,因此他只是一個文檔規範。以下是一個在React裏面使用JSX的例子:
var HelloMessage = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } }); React.render(<HelloMessage name="John" />, mountNode);
能夠看到如上使用了JSX的代碼,像是HTML和JavaScript代碼的混合體。不少人很不習慣這樣的編碼方式,認爲這和咱們一直倡導的表現和邏輯分離的思想相違背,是一種倒退。那麼React這樣的設計用意是啥呢?
React一個主要的設計理念是編寫簡單容易理解的代碼。HTML模板的做用是讓表現和邏輯分離,可是不少狀況下模板仍是嚴重依賴於業務邏輯,二者沒有辦法作到徹底的鬆耦合。稍微複雜一點的例子,好比AngularJS使用了一套獨特的機制來讓UI和邏輯交互,示例代碼以下。
<ul class="unstyled"> <li ng-repeat="todo in todoList.todos"> <input type="checkbox" ng-model="todo.done"> <span class="done-"></span> </li> </ul>
使用AngularJS的確從代碼角度作到表現和邏輯分離,可是在HTML裏面混入了大量的屬性標記,這些標記但從語義上很難理解,新手好比要整個熟悉Angular中每一個相似ng-*對應的用法及意義才能理解整個邏輯,因此有必定的入門門檻。如上例子使用JSX方式編寫以下:
render: function () { var lis = this.todoList.todos.map(function (todo) { return ( <li> <input type="checkbox" checked={todo.done}> <span className="done-{todo.done}">{todo.text}</span> </li>); }); return ( <ul class="unstyled"> {lis} </ul> ); }
能夠看到,JSX中除了使用HTML標記以外,並無複雜的標記。這種天然而直觀的方式直接下降了React的學習門檻而且讓代碼更容易理解。
JSX只是簡化了React的使用難度,但並非必須的。在React中也能夠不使用JSX,而是使用原生JavaScript的方式編寫代碼。在實際使用過程當中也是把JSX轉換成了JavaScript代碼來運行的。React官方網站上提供了一個在線轉換JSX到原生JavaScript代碼的工具,經過這個工具也能夠體會JSX使用上的優點及其內在原理。
Flux是另一個獨立於React的架構。之因此說Flux是一個架構而不是框架或者類庫,是由於Flux僅僅用於配合React框架來處理組件和數據之間的交互。簡單來講Flux就是用於管理數據流。和其餘MVC框架倡導的雙向數據綁定不一樣,Flux使用了單向數據綁定的機制,即數據模型到視圖的流動。以下兩個圖展現MVC和Flux之間的差別:
Flux中主要使用了三個概念:Dispatcher、Action和Store。這三個概念區別於MVC的model、view和controller概念,由於MVC中更多的是數據雙向綁定。
Actions是用於傳遞數據給Dispatcher的操做集合。Action可能來自於用戶界面的操做,也多是服務器端的數據更新。
Dispatcher是一個全局的分發器,接受Action,並傳遞給註冊的回調函數。
Stores包含了應用的狀態及註冊到Dispatcher的回調函數,這些函數用於處理業務邏輯。
和React Views最密切的是Store,React view從Store取得state和其餘數據,並更新界面。
從以上的React相關設計能夠看出,React是以下降前端開發的複雜度爲原則的。使用React編寫的代碼也易於理解,因此適合大規模多人開發,能提升項目的開發效率和質量。