原文地址:http://www.csdn.net/article/2015-08-04/2825370-reactcss
2004年,對於前端社區來講,是里程碑式的一年。Gmail橫空出世,它帶來基於前端渲染的原生應用級別的體驗,相對於以前的服務端渲染網頁可謂提高了一個時代,觸動了用戶的G點。自此,前端渲染的網站成爲無數開發者追逐的方向。html
爲了更好地開發前端渲染的「原生級別的」網站,包括Backbone和Angular在內的一系列前端框架應運而生,並迅速得到了大規模的採用。可是很快地,新的性能和SEO問題也接踵而來。幾經嘗試後,Twitter甚至從前端渲染重回服務器渲染,而Strikingly也面對過一樣棘手的問題。前端
2014年,React進入咱們的視線。讓人耳目一新的是,對於其餘開源框架遇到的種種問題,React都自信地給出瞭解答。幾乎沒有猶豫,咱們開始使用React來重構Strikingly。若干年後,當咱們回望,也許會發現,2014年也是前端社區里程碑式的一年。react
React簡介編程
React到底是什麼?Facebook把它簡單低調地定義成一個「用來構建UI的JavaScript庫」。這個定義也許會讓咱們聯想到許多JavaScript模板語言(好比Handlebars和Swig),或者早期的控件庫(好比YUI和Dojo),可是React所基於的幾個核心概念使它與那些模板和控件庫迥然不一樣。事實上這幾個核心概念很是超前,已經給整個前端世界帶來了衝擊性的影響。它們包括:後端
這幾條簡單的原則放在一塊兒帶來了大量的好處:設計模式
咱們來看一個例子:瀏覽器
這個React版的Hello World已經展示了React的一些核心特性。首先,HelloMessage是一個React組件;建立React應用的時候,咱們老是以組件爲出發點。每一個組件的核心是一個render方法,在其中咱們把這個組件的props和state拼裝到一個最終要渲染的模板中,而後返回這個模板(確切地說這裏是一個UI描述而不是傳統意義上的模板)。這段代碼裏看起來像HTML同樣的部分就是著名的JSX語法,它是在React中描述「模板」的最佳方式。前端框架
如今,以var開頭的第一段裏咱們定義了一個叫HelloMessage的組件;下面的React.render這一行所作的,則是把這個組件渲染到document.body裏——也就是咱們實際的頁面上。但在使用〈HelloMessage/〉的時候,咱們作了另外一件事:name="John"。看起來很像HTML中的元素屬性,可是既然JSX不是HTML,這個語法的做用是什麼呢?實際上,這就是咱們向React組件傳入props的方式。回頭看第一段,咱們能夠看到在組件的內部有對this.props.name的引用。這個name就是咱們剛剛指定的John!服務器
看到這裏,若是你熟悉jQuery的話也許在想,這與$(document.body).html('Hello John') 有什麼根本區別呢?
這就是虛擬DOM出場的地方了。咱們像寫HTML同樣寫JSX,可是JSX並不會直接變成HTML和DOM。在幕後,React維護着一個虛擬DOM,而實際上被瀏覽器直接操做的「物理」DOM只是這個虛擬DOM的投影。虛擬DOM不依賴於瀏覽器環境,它能夠運行在任何JavaScript執行環境。這就讓下面的代碼成爲可能:
若是第二行有點眼熟,你沒有猜錯——這段代碼發生在服務器端!是的,一樣的 HelloMessage,咱們不只可讓React在前端渲染到頁面,一樣能夠在後端直接渲染成HTML字符串,而後把它返回給前端。服務端預渲染就這麼天然地發生了。
React帶來的革命性創新是前端世界過去幾年最激動人心的變化。自從接觸React以來,咱們深信React會完全改變客戶端開發者(包括前端、iOS和Android)的開發體驗。在下面的篇幅裏,咱們想從四個大的方向——目標平臺(Targets)、數據處理(Data)、工具(Tools)和新的挑戰——分享一下React生態系統和社區的進展和將來趨勢。
目標平臺
對於虛擬DOM的討論,不少人會說速度快過於真正的DOM。這樣的討論可讓人快速入門理解React,可是真正寫過React應用的人會明白速度並非虛擬DOM的精髓。咱們認爲虛擬DOM的存在幫助咱們作到了兩件事。第一是申明式UI。經過虛擬DOM,UI再也不是一個不斷被更變的DOM,你只要申明UI是怎麼生成的,React會自動幫你把UI的改變渲染到真正的DOM上。這種新的思惟方式讓你能夠不用手動操做真正的DOM。第二是多Target。咱們一直在講Web,但React讓咱們作到Web之外的Target。虛擬DOM更像是UI虛擬機,自動幫你映射到真正的實現上,能夠是瀏覽器DOM、iOS UI、Android UI。甚至有人作到了React映射到終端文本UI。
多Targets是React社區經常在討論的主要話題之一。多Targets的根本是提升開發者體驗。開發者體驗(DX,Developer Experience)是在React社區裏多次被提起的概念。如何在保持同樣的用戶體驗下,提升開發者體驗,是包括React在內的前端社區正在思考的問題。事實上任何一家有多客戶端的公司都面臨着這樣同一個問題:在各類客戶端語言裏從新造輪子。開發者須要學習新的語言、寫和維護相似的功能。提高客戶端開發者體驗就是減小學習成本和維護成本。這就是React提倡的「Learn once,write everywhere」。
最近也有一些鼓舞人心的消息。Facebook內部Ads Manager iOS版本由7位前端工程師用React Native花了5個月完成。而Android版本,是同一班人,3個月內完成。代碼重用率達到了87%。
多Targets也能夠是在單個平臺更深度的結合。來自React核心團隊的Sebastian Markbåge在ReactEurope大會上給了一個讓人目瞪口呆的演講《DOM as a Second-class Citizen》。演講中他暢想React直接輸出到瀏覽器架構的底層(圖1瀏覽器的渲染架構,圖2爲Sebastian Markbåge認爲React能夠作的事情)。
圖1 瀏覽器的渲染架構
圖2 Sebastian Markbåge認爲React還能夠作不少事情
姑且不談該不應這麼作,經過虛擬DOM打開了這樣的機會就已經讓咱們興奮不已了。也說明了Facebook在設計React時已經考慮到超越DOM。想法確實很超前。
【服務端預渲染(Pre-rendering)】
對於其餘主流前端框架,頁面SEO和首次打開速度的問題都很讓人頭疼。Twitter當年由於首次打開速度過於慢甚至重回服務器渲染方案。一直以來人們一直在尋找一種只須要編寫一次UI組件,先後端同時都能渲染的方案。若是能作到的話,咱們就能夠在首次打開頁面時先用服務端渲染頁面HTML,當瀏覽器收到後已經能夠顯示頁面。這樣SEO和首次打開速度都能被解決。這種完美方案社區裏稱之爲Isomorphic/Universal App。
React原生支持了Pre-rendering(服務端渲染)。因爲有虛擬DOM,也就意味着咱們只須要後端運行JavaScript引擎就能渲染整個DOM。目前主流後端語言均可以運行V8 JavaScript引擎。好比Strikingly的後端使用Ruby on Rails,只須要使用開源的react-rails gem就能夠在Rails後端渲染前端React組件。
使用服務端渲染時要注意window和document這些瀏覽器纔有的全局變量是不存在的。React組件提供這兩個lifecycle hook:componentDidMount和componentDidUpdate在服務器不會被運行,只有在前端纔會運行。使用服務器渲染時若是要使用任何瀏覽器纔有的變量須要把代碼放到這兩個lifecycle hook定義裏。
數據處理
React定義本身爲MVC中的View。這讓前端開發者從V開始去思考UI設計。但如今針對數據操做和獲取方式,社區裏尚未一種公認的方法。這也是任何寫React應用時最難處理的地方。
【Flux】
對於M和C,Facebook提出了Flux的概念。Flux是一個專門爲React設計的應用程序架構:應用程序由Dispatcher、Store和View組成,其中的View就是咱們的React組件。Flux的核心是如圖3所示的單向數據流動。
圖3 單向數據流動爲Flux的核心
應用程序中的任何一次數據變化都做爲Action發起,通過Dispatcher分發出去,被相關的Store接收到並整合,而後做爲props和state提供給View(React組件)。當用戶在View上作了任何與數據相關的交互,View會發起新的Action,開啓一次新的數據變化週期。這種單向性使Flux在高層次上比傳統MVC架構和以Angular和Knockout爲表明的雙向數據綁定容易理解得多,大大簡化了開發者的思考和Debug過程。
在Facebook把Flux做爲一種設計模式(而不是已經作好的框架)宣佈以後,幾乎每月出現一新的Flux庫,他們都有各自的特點,有的對服務器渲染支持比較好,有的運用了更多函數式編程的概念。不少Flux庫更像是實驗,這有助於React生態的生長,但不能否認的是,將來會有大量Flux庫慢慢死去,而只有少數會存留下來或進行合併。
【GraphQL】
在構建大型前端應用時,前端和後端工程師經過API的方式進行合做。API也是雙方的協議。如今主流的方式是RESTful API,然而在實踐中,咱們發現RESTful在一些真實生產環境的需求下不是很適用。每每咱們須要構建自定義endpoint,而這違背了RESTful的設計理念。
舉個例子,咱們想要顯示論壇帖子、做者和對應的留言。咱們分別要發出三個不一樣的請求。第二個請求依賴第一個請求結果返回的user_id,前端須要寫代碼協調請求之間的依賴。分別發出三個不一樣請求在移動端這種網絡不穩定的環境下效果很不理想。
爲解決這類問題,工程師會自定義一些endpoint。對於這個例子,咱們能夠創建一個/feeds的endpoint,集合了全部前端須要的結果:
可是咱們在某些場景上可能只須要post和user,不想要comments。這時難道要再定義一個feeds_without_comments的endpoint?隨着需求的改變,自定義endpoint的方法每每使得API接口變得累贅,違背了RESTful的設計理念。而任何前端工程師須要的數據一旦要改變都須要後端工程師的配合,這下降了產品的迭代速度。
來自Facebook的GraphQL是我認爲目前最接近完美的解決方法。後端工程師只須要定義能夠被查詢的Type System,前端工程師就可使用GraphQL自定義查詢。GraphQL查詢語句只須要形容須要返回的數據形狀:
{ post(id:1){ id, title, user{ id, name }, comments{ id, name, comment } } }
GraphQL服務器就會返回正確的JSON格式:
GraphQL也原生支持了API版本控制,讓你能夠同時共存多個版本的客戶端(包括Web和Mobile)。這些都會減小客戶端工程師和後端工程師的耦合度,提升生產力。
今年7月剛推出了GraphQL的規範並開源了JavaScript GraphQL庫。然而要讓GraphQL成爲主流,Facebook須要打造一個像React這樣的生態系統。要想在你本身的應用上用GraphQL還必需要有後端語言提供GraphQL庫的支持。好比Strikingly須要GraphQL Ruby庫。這不只僅須要前端工程師。咱們認爲這將會比React生態系統更難創建(見圖4所示)。Facebook須要整個社區的參與才能達到。
圖4 GraphQL生態系統
【Relay】
Relay是Facebook提出的在React上應用GraphQL的方案。React的基礎單位是組件(Component),構建大型應用就是組合和嵌套組件。以組件爲單位的設計模式是目前社區裏最承認的,這也是前端世界的趨勢之一。每一個組件須要的數據也應該在組件內部定義。Relay讓組件能夠自定義其所須要GraphQL數據格式,在組件實例化的時候再去GraphQL服務器獲取數據。Relay也會自動構建嵌套組件的GraphQL查詢,這樣多個嵌套的組件只須要發一次請求。Relay將會在8月份開源。
【Immutability】
React社區接受了不少函數式編程的想法,其中受Clojure影響很深。對Immutable數據的使用就是來自Clojure社區。當年Om,這個用ClojureScript寫的React wrapper在速度上竟然完虐原生JavaScript版本的React。這讓整個社區都震驚了。其中一個緣由就是ClojureScript使用了Immutable數據。React社區裏也冒出了Immutable.js,這讓JavaScript裏也能使用Immutable數據,完美彌補了JavaScript在負責數據對象比較的先天性不足。Immutable.js也成爲了構建大型React應用的必備。甚至有在討論是否把Immutable.js直接歸入JavaScript語言中。咱們認爲小型應用不會遇到虛擬DOM的性能瓶頸,引入Immutable.js只會讓數據操做很累贅。
工具
工欲善其事,必先利其器。React的火爆得力於來自社區的工具,而React也推進了這些工具的進步。這裏咱們想介紹幾個React社區裏比較受歡迎的工具。
【Webpack】
在React裏,因爲須要用到JSX,使用Webpack或Browserify這類工具編譯代碼已經漸漸成爲前端工程師工做流程的一部分。Webpack是一款強大的前端模塊管理和打包工具(見圖5所示)。這裏列出它的一些特性:
圖5 前端模塊管理和打包工具Webpack
【Babel】
ECMAScript 6(ES6)規範在今年四月剛敲定,React社區基本全面擁抱ES6。但目前還有不少瀏覽器不支持ES6。使用像Webpack這樣的工具編譯代碼使得咱們能夠在開發時使用ES6(或者更新版本),在上線前編譯成ES5。編譯工具中最引人注意的是Babel。前身爲ES6to5,Babel是目前社區最火的ES6編譯到ES5的代碼工具,Facebook團隊甚至已經決定轉用Babel而再也不維護以前內部使用的jstranform。經過Loader機制,Webpack能夠很是簡易地和Babel結合應用。
【React-hot-reload】
在開發任何大型前端應用過程當中,咱們經常會由於一些小錯誤就須要從新刷新整個頁面。React-hot-reload嘗試解決這個問題,提升開發效率。他使用了Webpack的Hot Module Replacement功能,動態替換React組件的lifecycle hook定義,不用刷新頁面也能夠更新代碼變化。
【React Developer Tool】
這款Facebook官方推出的Chrome插件可讓你方便地在瀏覽器中直接查看React的組件結構。安裝後,在Chrome開發者工具中會多出一個React Tab。界面就像DOM Inspector同樣,只不過是看React組件結構關係。是開發React應用不可多得的工具之一。
挑戰
React正在快速開拓着它的疆界,這意味在得到新的喜悅的同時,咱們也面臨着許多新的挑戰。如今圍繞着幾個大的議題,React社區仍沒有達成定論,每週甚至天天都有新的實驗項目在嘗試這些問題的解決。
【動畫】
一直以來你們都對動畫應該在React裏怎麼表達爲狀態感到困惑。Cheng Lou的React Tween State是咱們認爲最符合React思惟的作法。把位移存在State裏,而後經過JavaScript動態渲染新的位置。不過你們對該作法是否能達到滿意的速度一直持有保留態度。在今年ReactEurope的演講中,他爲咱們展示出了出色的效果和速度,很是值得一看。
在Strikingly,咱們對於動畫則採起了比較實用主義的處理方式:咱們定義了一些容器組件,好比〈JQFade/〉和〈JQSlide/〉,在其中調用jQuery的動畫方法來實現相應的Transition。這種方式在理論上並不徹底符合React的精神,不過到如今爲止仍是可以知足咱們需求的。
【Flux庫與Relay】
正如上文已經提到過的,目前Flux的各類實現可謂是百花齊放,其中還並無出現一個具備權威性的事實標準。Relay一樣也是剛剛孵化不久的新生概念——全部這些意味着雖然Flux+Relay會帶來生產力的飛昇,要實際用上它們咱們還要待以時日。
【CSS】
CSS是一個有趣的話題:彷佛全部人都以爲當前的CSS有深入的缺陷,可是對於怎麼解決這些缺陷你們的意見卻分紅了兩派各不相讓:一派認爲CSS「能夠被修好」,而且致力於修好它,由此誕生了cssnext這樣的項目;另外一派認爲CSS從根本上做爲誕生於一個古老時代的東西,已經不能適應大規模、組件化的現代開發流程,這一思想集中反映在Christopher Chedeau的演講《React: CSS in JS》中;在其中他提出了CSS的七個根本問題,而後指出在JavaScript中直接使用inline CSS能夠幾乎「免費」地解決全部這些問題。在傳統的Web開發最佳實踐中inline CSS一直是被壓制的反面實踐,如今咱們卻可以以一個全新的視角看待它,這也完美地例證了React真的是在給整個前端世界帶來根本性的推進。
總結
在不久前的JSConf 2015上赫門提出了前端的摩爾定理:前端每18月會難一倍。前端之因此變化這麼快,是由於咱們如今面臨着史無前例的工程化挑戰。今天的前端複雜度跟幾年前徹底不是一個等級。這也促使社區要找到在這種複雜度下能保持開發效率和開發體驗的工具和設計模式。React社區從其餘領域(遊戲渲染、ClojureScript、函數式編程)偷師學藝,結合前端面臨的獨特問題,提出了一系列解決方案。React社區在各方面都推進着前端社區往前進。這對整個社區都是好事。咱們也但願前端各個框架能夠互相學習,共同推進整個社區的發展。