React是Facebook開發的一款JS庫,用於構建用戶界面的類庫。javascript
它採用聲明式範例,能夠傳遞聲明代碼,最大限度地減小與DOM的交互。java
特色:node
在Web開發中,咱們總須要將變化的數據實時反應到UI上,這時就須要對DOM進行操做。而複雜或頻繁的DOM操做一般是性能瓶頸產生的緣由。react
React爲此引入了虛擬DOM(Virtual DOM)的機制:算法
在瀏覽器端用Javascript實現了一套DOM API。基於React進行開發時全部的DOM構造都是經過虛擬DOM進行,每當數據變化時,React都會從新構建整個虛擬DOM樹,而後React將當前整個虛擬DOM樹和上一次的虛擬DOM樹進行對比,獲得虛擬DOM結構的區別,而後僅僅將須要變化的部分進行實際的瀏覽器DOM更新。瀏覽器
虛擬DOM做爲React的一大核心技術,瞭解其實現原理對於靈活應用有着很大幫助。性能優化
在咱們項目中申明一個組件是這樣的:app
react.createElement('div', null, [ // 建立一個img react.createElement('img', { src: "avatar.png", class: "profile" }), // 或者 react.createElement('h1', null, [[user.firstName, user.lastName].join(' ')]) ]);
最後,React都會轉換成相似這樣的基本對象:框架
{ tagName: 'div', // 節點包含的屬性 properties: { style: { color: '#fff' } }, // 子節點 children: [], // 節點的惟一標識 key: 1 }
而後,React把Javascript DOM模對象 轉換成 Javascript DOM節點樹:dom
function create(vds, parent) { !Array.isArray(vds) && (vds = [vds]); // 若是沒有父元素則建立個fragment來當父元素 parent = parent || document.createDocumentFragment(); var node; vds.forEach(function (vd) { // 若是是文字節點 if (isText(vd)) { // 建立文字節點 node = document.createTextNode(vd.text); } else { // 建立元素 node = document.createElement(vd.tag); } // 將元素塞入父容器 parent.appendChild(node); // 看看有沒有子VNode,有孩子則處理孩子VNode vd.children && vd.children.length && create(vd.children, node); // 看看有沒有屬性,有則處理屬性 vd.properties && setProps({ style: {} }, vd.properties, node); }); return parent; }
如今咱們獲得的是Javascript 實現的虛擬DOM樹,在一個事件循環中,當state或者preps變化時,React會建立一個新的虛擬DOM樹,最後進行差別渲染。
diff(previous:VTree, current:VTree) -> PatchObject
React分三種情景:
a. 分層對比
React 僅僅是嘗試把樹按照層級分解. 這完全簡化了複雜度, 並且也不會失去不少, 由於 Web 應用不多有 component 移動到樹的另外一個層級去。它們大部分只是在相鄰的子節點之間移動。
b. 基於key匹配
Keys是一個VNode的惟一識別,用於對兩個不一樣的VTree中的VNode作匹配的。經過key鎖定某個組件後,React就能夠直接對比這兩個差別DOM節點樹,複雜度爲O(n)。
因此這裏有個性能優化的技巧。假設你有一個key組件,他的key屬性爲foo,後續又將它改成bar,那麼React就會掉過DOM diff,同時徹底棄置div全部自元素,從頭渲染。在渲染大型子樹以免diff計算時,這樣的設計頗有用,由於咱們知道這種計算就是在浪費時間。
c. 基於自定義元素作優化
React提供自定義元素,因此匹配很簡單。React 只會匹配相同 class 的 component。
好比, 若是有個<Header>
被<ExampleBlock>
替換掉了,
React 會刪除掉 header 再建立一個example block
。咱們不須要化寶貴的時間去匹配兩個不大可能有類似之處的 component。
React在你調用 component 的 setState 方法的時候, 將其標記爲 dirty,到每個事件循環結束, React 檢查全部標記 dirty 的 component 從新繪製。每次調用 setState 會從新計算整個子樹.若是你想要提升性能, 儘可能少調用 setState。
最後, 你還有可能去掉一些子樹的從新渲染,若是你在 component 上實現function shouldComponentUpdate(nextProps, nextState) 的話,你根據 component 的前一個和下一個 props/state,告訴 React 這個 component 沒有更新, 也不須要從新繪製。