首先,咱們來看看 React 在世界範圍的熱度趨勢,下圖是關鍵詞「房價」和 「React」 在 Google Trends 上的搜索量對比,藍色的是 React,紅色的是房價,很明顯,人類對 React 的關注程度已經遠遠超過了對房價的關注。javascript
從這些數據中,你們能看出什麼?
能夠很明顯的看出,我在一本正經的扯淡。html
從2014年到如今,React、jQuery 和 Angular 的熱度趨勢對比,能夠很明顯的看到(上圖),React 在全球的熱度趨勢增加很是快。前端
上圖是 React 在國內的百度搜索指數,是拿 React 和 Nodejs 作了個對比,能夠看出 React 的關注度也已經逼近 nodejs。java
雖然在關注總量上 React 還遠不及 jQuery 和 Angular 等等,但它的增加幅度超乎你想象,你知道這意味着什麼嗎?這意味着關注 React,你就比大多數人走在了業界的前沿!node
那麼 React 究竟是什麼鬼?react
引用官網的簡介,」一個用來構建用戶界面的 javascript 庫」。git
React 起源於 Facebook 的內部項目,由於 FB 對市場上全部 JavaScript MVC 框架,都不滿意,就決定本身寫一套,用來架設 Instagram 的網站。作出來之後,發現這套東西很好用,就在2013年5月開源了。程序員
因爲 React 的設計思想極其獨特,屬於革命性創新,性能出衆,代碼邏輯卻很是簡單。因此,愈來愈多的人開始關注和使用,認爲它多是未來 Web 開發的主流工具。github
和 Backbone、Angular 等 MV* 框架不同,它只處理 View 邏輯 ,它只處理 View 邏輯,它只處理 View 邏輯。因此若是你喜歡它,你能夠很容易的將它接入到現有工程中,而後用 React 重寫 HTML 部分便可,不用修改邏輯。web
近幾年 web 領域的技術革新很是迅速,React 也是一項新技術…話說 React 出來也已經2年了,其實並不算什麼新技術了,只是在國內尚未普及開,這篇文章的目的也是幫助你們更快的理解 react 和認識 react 能給咱們帶來的價值。
React 這麼火,那麼它到底有什麼牛逼的地方?
上圖是2015年年初的數據
這是 Facebook 的好友動態頁面,也是 Facebook 訪問量最大的頁面沒有之一,經過 Chrome React 插件能夠看到這個頁面確實是用 React 實現的。 (有同事問我爲何關注柳巖,我說由於我是柳巖的球迷啊)
前面給你們來了一波前戲,相信你們已經有點火燒眉毛了,那麼,進入正題: 首先,先跟你們描述下 React 最特別的部分,聽完這部分你們基本就可以在腦海裏創建起一個 React 的大體印象。
而後是 React 的核心內容,聽完這部分你們待會回去就能夠開始寫代碼而後今天晚上發佈上線了。 最後是 React 可以給咱們實際帶來的價值,咱們不做無心義的代碼重構。
首先,咱們來看 JSX——
JSX 使用的是預編譯模板,React 提供了一個預編譯工具,叫 react-tools,能夠經過 npm 命令安裝,通常是在開發時期運行,運行後它會啓動一個監聽程序,實時監聽 JSX 源碼的修改,而後自動編譯爲 JS 代碼。
你們留意下,render() 方法裏的被編譯成了 React.createElement(),它這麼作,目的就是爲了實現虛擬 DOM。
接下來咱們來了解 React 最大的亮點 ———— 虛擬 DOM。
傳統 web app 和 DOM 直接交互,由 App 來控制 DOM 的構建和渲染、元素屬性的讀寫、事件的註冊和銷燬等等。 當新產品剛上線的時候,這種作法看起來也挺好。但隨着產品功能愈來愈豐富、代碼量愈來愈多、開發團隊人員愈來愈多 —————
一年後
你的代碼可能會變成這樣。
固然,合理的代碼規劃可以避免這類問題,但團隊裏不免會有擅長屠宰式編程的同窗,分分鐘把你代碼改的面目全非。
這時,React 的虛擬 DOM 和單項數據流就能很好的解決這個問題。
虛擬 DOM 則是在 DOM 的基礎上創建了一個抽象層,咱們對數據和狀態所作的任何改動,都會被自動且高效的同步到虛擬 DOM,最後再批量同步到 DOM 中。
虛擬 DOM 會使得 App 只關心數據和組件的執行結果,中間產生的 DOM 操做不須要 App 干預,並且經過虛擬 DOM 來生成 DOM,會有一項很是可觀收益——-性能。
全部人都知道 DOM 慢,渲染一個空的 DIV,瀏覽器須要爲這個 DIV 生成幾百個屬性,而虛擬 DOM 只有6個,因此減小沒必要要的重排重繪以及 DOM 讀寫可以對頁面渲染性能有大幅提高。
那麼咱們來看看虛擬 DOM 是怎麼作的:React 會在內存中維護一個虛擬 DOM 樹,當咱們對這個樹進行讀或寫的時候,其實是對虛擬 DOM 進行的。當數據變化時,而後 React 會自動更新虛擬 DOM,而後拿新的虛擬 DOM 和舊的虛擬 DOM 進行對比,找到有變動的部分,得出一個 Patch,而後將這個 Patch 放到一個隊列裏,最終批量更新這些 Patch 到 DOM 中。
這樣的機制能夠保證即使是根節點數據的變化,最終表如今 DOM 上的修改也只是受這個數據影響的部分,能夠保證很是高效的渲染。
但這樣也是有必定的缺陷的——首次渲染大量DOM時由於多了一層虛擬 DOM 的計算,會比 innerHTML 插入方式慢,因此使用時須要確保不要一次性渲染大量 DOM。
幾個UI組件的渲染性能對比
http://mathieuancelin.github.io/js-repaint-perfs/
一個最基本的 React 組件由數據和 JSX 兩個主要部分構成,咱們先來看看數據。
這是一個簡單單完整的 React 組件【類】,細節你們先不用太在乎細節,瞭解機制就能夠。
props 主要做用是提供數據來源,能夠簡單的理解爲 props 就是構造函數的參數。 state 惟一的做用是控制組件的表現,用來存放會隨着交互變化狀態,好比開關狀態等。
JSX 作的事情就是根據 state 和 props 中的值,結合一些視圖層面的邏輯,輸出對應的 DOM 結構。
前面咱們知道了一個簡單的組件的構成,但單個的組件確定不能知足實際需求,咱們須要作的是將這些獨立的組件進行組裝,同時找出共性的部分進行復用。
好比這樣一個場景
咱們以這樣一個界面爲例,能夠看出,裏面的 <Pub/> <Article/> 都是最細粒度的組件,是能夠複用的。 首先,咱們來看下 Article 的代碼——
這個就是咱們分解出來的 Article 組件,它須要2個屬性,article 對象和 showImage。article 對象包含圖片、地址、標題、描述信息,showImage 是一個布爾類型,用來判斷是否須要顯示成一個圖片。
這個組件自己的實現能夠很簡單也能夠很複雜,但使用者可不關心你的內部實現,使用者關心的是組件須要什麼參數就能夠了。
外國人的組件化思想比咱們國內的普及程度高不少,不僅侷限於軟件開發,包括實體行業的咖啡機、加油站、 兒童搖搖車都有這種設計思想在裏面。
但願你們在設計模塊的時候,也儘量將組件邏輯對外透明,來減小維護成本。
你們留意一下標虛線的部分,這裏複用了 Article 組件。這時的 Article 組件看起來就是一個普通的標籤而已,簡單吧。
這個是熱問組件,也複用了 Article 組件。這就是 React 如絲般順滑的組件複合。
這個,叫作竹筧,是中日傳統禪文化中常見的庭院裝飾品,它的構造可簡單可複雜,但原理很簡單,好比這個竹筧,水從竹筧頂部入口流入內部,並按照固定的順序從上向下依次流入各個小竹筒,而後驅動水輪轉動。對於強迫症患者來講,觀賞竹筧的絕對是一種很享受的過程的最愛,你會發現這些小玩意居然能這麼流暢的協調起來,好神奇。
若是竹筧是一個組件的話,那麼水就是組件的數據流。
在 React 中,數據流是自上而下單向的從父節點傳遞到子節點,因此組件是簡單且容易把握的,他們只須要從父節點提供的 props 中獲取數據並渲染便可。若是頂層組件的某個 prop 改變了,React 會遞歸地向下遍歷整棵組件數,從新渲染全部使用這個屬性的組件。
這個是前面看到的 Article 題組件,擁有一個叫作 articles 的屬性。
在組件內部,能夠經過 this.props 來訪問 props,props 是組件惟一的數據來源,對於組件來講:
props 永遠是隻讀的。
組件的屬性類型若是不進行聲明和驗證,那麼極可能使用者傳給你的屬性值或者類型是無效的,那會致使一些意料以外的故障。好在 React 已經爲咱們提供了一套很是簡單好用的屬性校驗機制——
React 有一個 PropTypes 屬性校驗工具,通過簡單的配置便可。當使用者傳入的參數不知足校驗規則時,React 會給出很是詳細的警告,定位問題不要太容易。
PropTypes 包含的校驗類型包括基本類型、數組、對象、實例、枚舉——
以及對象類型的深刻驗證等等。若是內置的驗證類型不知足需求,還能夠經過自定義規則來驗證。 若是某個屬性是必須的,在類型後面加上 .isRequired 便可。
React 的一大創新,就是把每個組件都當作是一個狀態機,組件內部經過 state 來維護組件狀態的變化,這也是 state 惟一的做用。
state 通常和事件一塊兒使用,咱們先看 state,而後看看 state 和事件怎樣結合。
這是一個簡單的開關組件,開關狀態會以文字的形式表如今按鈕的文本上。
首先看 render 方法,返回了一個 button 元素,給 button 註冊了一個事件用來處理點擊事件,在點擊事件中對 state 的 on 字段取反,並執行 this.setState() 方法設置 on 字段的新值。一個開關組件就完成了。
組件渲染完成後,必須有 UI 事件的支持才能正常工做。
React 經過將事件處理器綁定到組件上來處理事件。
React 事件本質上和原生 JS 同樣,鼠標事件用來處理點擊操做,表單事件用於表單元素變化等,Rreact 事件的命名、行爲和原生 JS 差很少,不同的地方是 React 事件名區分大小寫。
好比這段代碼中,Article 組件的 section 節點註冊了一個 onClick 事件,點擊後彈出 alert。
有時候,事件的處理器須要由組件的使用者來提供,這時能夠經過 props 將事件處理器傳進來。
這個是剛纔那個 Article 組件的使用者,它提供給 Article 組件的 props 中包含了一個 onClick 屬性,這個 onClick 指向這個組件自身的一個事件處理器,這樣就實現了在組件外部處理事件回調。
這是一個 React 組件實現組件可交互所需的流程,render() 輸出虛擬 DOM,虛擬 DOM 轉爲 DOM,再在 DOM 上註冊事件,事件觸發 setState() 修改數據,在每次調用 setState 方法時,React 會自動執行 render 方法來更新虛擬 DOM,若是組件已經被渲染,那麼還會更新到 DOM 中去。
這些是 React 目前支持的事件列表。
React 的組件擁有一套清晰完整並且很是容易理解的生命週期機制,大致能夠分爲三個過程:初始化、更新和銷燬,在組件生命週期中,隨着組件的 props 或者 state 發生改變,它的虛擬 DOM 和 DOM 表現也將有相應的變化。
首先是初始化過程,這裏會着重講,須要充分理解。
組件類在聲明時,會先調用 getDefaultProps() 方法來獲取默認 props 值,這個方法會且只會在聲明組件類時調用一次,這一點須要注意,它返回的默認 props 由全部實例共享。
在組件被實例化以前,會先調用一次實例方法 getInitialState() 方法,用於獲取這個組件的初始 state。
實例化以後就是渲染,componentWillMount 方法會在生成虛擬 DOM 以前被調用,你能夠在這裏對組件的渲染作一些準備工做,好比計算目標容器尺寸而後修改組件自身的尺寸以適應目標容器等等。
接下來就是渲染工做,在這裏你會建立一個虛擬DOM用來表示組件的結構。對於一個組件來講,render 是惟一一個必須的方法。render方法須要知足這幾點:
只能經過 this.props 或 this.state 訪問數據
只能出現一個頂級組件
能夠返回 null、false 或任何 React 組件
不能對 props、state 或 DOM 進行修改
須要注意的是,render 方法返回的是虛擬 DOM。
渲染完成之後,咱們可能須要對 DOM 作一些操做,好比截屏、上報日誌、或者初始化 iScroll 等第三方非 React 插件,能夠在 componentDidMount() 方法中作這些事情。固然,你也能夠在這個方法裏經過 this.getDOMNode() 方法取得最終生成 DOM 節點,而後對 DOM 節點作愛作的事情,但須要注意作好安全措施,不要緩存已經生成的 DOM 節點,由於這些 DOM 節點隨時可能被替換掉,因此應該在每次用的時候去讀取。
組件被初始化完成後,它的狀態會隨着用戶的操做、時間的推移、數據更新而產生變化,變化的過程是組件聲明週期的另外一部分 ——
更新過程。
當組件已經被實例化後,使用者調用 setProps() 方法修改組件的數據時,組件的 componentWillReceiveProps() 方法會被調用,在這裏,你能夠對外部傳入的數據進行一些預處理,好比從 props 中讀取數據寫入 state。
默認狀況下,組件在 setState() 以後,React 會遍歷這個組件的全部子組件,進行「灌水」,將 props 從上到下一層一層傳下去,並逐個執行更新操做,雖然 React 內部已經進行過不少的優化,這個過程並不會花費多少時間,可是程序員裏永遠不缺少長期性能飢渴的同窗,不用擔憂,React 有一個可以解決你性能飢渴的辦法—— shouldComponentUpdate() ——有時候,props 發生了變化,但組件和子組件並不會由於這個 props 的變化而發生變化,打個比方,你有一個表單組件,你想要修改表單的 name,同時你可以確信這個 name 不會對組件的渲染產生任何影響,那麼你能夠直接在這個方法裏 return false 來終止後續行爲。這樣就可以避免無效的虛擬 DOM 對比了,對性能會有明顯提高。
若是這個時候有同窗仍然飢渴難耐,那麼你能夠嘗試不可變數據結構(用過 mongodb 的同窗應該懂)。
組件在更新前,React 會執行 componentWillUpdate() 方法,這個方法相似於前面看到的 componentWillMount() 方法,惟一不一樣的地方只是這個方法在執行的時候組件是已經渲染過的。須要注意的是,不能夠在這個方法中修改 props 或 state,若是要修改,應當在 componentWillReceiveProps() 中修改。
而後是渲染,React 會拿此次返回的虛擬 DOM 和緩存中的虛擬 DOM 進行對比,找出【最小修改點】,而後替換。
更新完成後,React 會調用組件的 componentDidUpdate 方法,這個方法相似於前面 componentDidMount 方法,你仍然能夠在這裏能夠經過 this.getDOMNode() 方法取得最終的 DOM 節點。
香港電影結尾常常看到一個劇情,就是英雄戰勝了壞人,而後警察出來擦屁股——
componentWillUnmount 除了擦屁股什麼也作不了。
你能夠在這個方法中銷燬非 React 組件註冊的事件、插入的節點,或者一些定時器之類。這個過程可能容易出錯,好比綁定了事件卻沒銷燬,這個 React 可幫不了你,你本身約的炮,含着淚也要打完。
下面咱們來看看 React 怎樣結合 nodejs 實現服務端渲染。
服務端渲染有多快我就很少說了。
由於有虛擬 DOM 的存在,React 能夠很容易的將虛擬 DOM 轉換爲字符串,這便使咱們能夠只寫一份 UI 代碼,同時運行在 node 裏和和瀏覽器裏。
var html = React.renderToString(elem);
在 node 裏將 react 組件 HTML 渲染爲 HTML,一句代碼便可。
不過圍繞這個 renderToString 咱們還要作一些準備工做:
從後臺 server 或數據庫等來源拉取數據
調用 React.renderToString() 方法來生成 HTML
最後發送 HTML 和數據給瀏覽器
代碼就不貼了,你們自行腦補。
須要注意的是這裏的 JSON 字符串中可能出現 </script> 結尾標籤或 HTML 註釋,可能會致使語法錯誤,這裏須要進行轉義。
頁面的示例代碼原本打算用你們更熟悉的 HTML,但發現代碼量太多了,因此換成了 jade 代碼,沒用過 jade 的同窗也順便了解一下,我也順便給 jade 打個廣告。 這個頁面作了這幾件事:
將前面在 action 裏生成的 HTML 寫到 #container 元素裏
引入必須的 JS 文件
獲取 action 提供的數據
渲染組件
這就是 React 的服務端渲染,組件的代碼先後端均可以複用。
是否是感受 React 挺牛逼的?還沒完!
React 可以用一套代碼同時運行在瀏覽器和 node 裏,並且可以以原生 App 的姿式運行在 iOS 和 Android 系統中,即擁有了 web 迭代迅速的特性,又擁有原生 App 的體驗。
這個姿式叫作 React-Native。
這是 React 和 React-Native 在 github 上的數據,能夠看出 React-Native 也是至關熱門——由於 React-Native 可以使 React 的價值最大化,這個價值是什麼呢——對業務來講,意味着不須要爲了作終端版本就招聘和前端等量人力的終端開發,同時意味着咱們成爲全棧工程師有了一個捷徑。
瞭解 iOS 開發的同窗都知道,水果公司對應用上架的審覈效率實在讓人無力吐槽,不少團隊上一個版本還沒審覈結束,下一個版本就已經作好了。而 React-Native 支持從網絡拉取 JS,這樣 iOS 應用也可以像 web 同樣實現快速迭代了。
上圖就是 react-native 的調試過程,以 iOS 爲例
啓動 xcode build
在模擬器中按下 Command + D 打開菜單,選擇 Debug in Chrome
在 Chrome dev tools 中調試
固然,react 並非完美的,在實際使用時你也會發現她的一些缺點,好比:
(若是隻是作安卓 app 開發,那麼「蘋果兩件套+開發者證書」不是必須的,在 windows 下面開發便可。)
最後,你們在使用 react 開發時,可能會須要安裝 React developer tools
最後是一點參考資料
書山有路勤爲徑,react 即是那通往『全棧工程師』的捷徑。
掃一掃,關注 全棧技術 公衆號