標籤:pcl const rem xtend ble 相同 提升 segment 快速
轉自:1190000006100489
React: 一個用於構建使用者介面的JAVASCRIPT庫.
React僅僅專註於UI層;它使用虛擬DOM技術,以保證它UI的高速渲染;它使用單向資料流,因此它資料繫結更加簡單;那麼它內部是如何保持簡單高效的UI渲染呢?
React不直接操作DOM,它在記憶體中維護一個快速響應的DOM描述,render方法返回一個DOM的描述,React能夠計算出兩個DOM描述的差異,然後更新瀏覽器中的DOM。
就是說React在接收到props或者state更新時,React就會通過前面的方式更新UI。就算重新使用ReactDOM.render(<Component />, mountNode)
,它也只是當作props更新,而不是重新掛載整個組件。所以React整個UI渲染是比較快的。
但是,這裡面有幾個問題
1. 如果更新的props和舊的一樣,這個時候很明顯UI不會變化,但是React還是要進行虛擬DOM的diff,這個diff就是多餘的效能損耗,而且在DOM結構比較複雜的情況,整個diff會花費較長的時間。
2. 既然React總是要進行虛擬DOM的diff,那麼它的diff規則是什嗎?怎麼利用?
PureRenderMixin
針對第一個問題React給我們提供了 PureRenderMixin。如果React組件是純函數的,就是給組件相同的props和state組件就會展現同樣的UI,可以使用這個Minxin來最佳化React組件的效能。
var PureRenderMixin = require(‘react-addons-pure-render-mixin‘);React.createClass({ mixins: [PureRenderMixin], render: function() { return <div className={this.props.className}>foo</div>; }});
ES6中的用法是
import PureRenderMixin from ‘react-addons-pure-render-mixin‘;class FooComponent extends React.Component { constructor(props) { super(props); this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); } render() { return <div className={this.props.className}>foo</div>; }}
PureRenderMixin的原理就是它實現了shouldComponentUpdate,在shouldComponentUpdate內它比較當前的props、state和接下來的props、state,當兩者相等的時候返回false,這樣組件就不會進行虛擬DOM的diff。
這裡需要注意:
PureRenderMixin內進行的僅僅是淺比較對象。如果對象包含了複雜的資料結構,深層次的差異可能會產生誤判。僅用於擁有簡單props和state的組件。
shouldComponentUpdate
React雖然提供簡單的PureRenderMixin來提升效能,但是如果有更特殊的需求時怎麼辦?如果組件有複雜的props和state怎麼辦?這個時候就可使用shouldComponentUpdate來進行更加定製化的效能最佳化。
boolean shouldComponentUpdate(object nextProps, object nextState) { return nexprops.id !== this.props.id;}
在React組件需要更新之前就會調用這個方法,如果這個方法返回false,則組件不更新;如果返回true,則組件更新。在這個方法內部可以通過nextProps和當前props,nextState和當前state的對比決定組件要不要更新。
如果對比的資料結構比較複雜,層次較深,對比的過程也是會有較大效能消耗,又可能得不償失。
這個時候immutable.js就要登場了,也是fb出品,有人說這個架構的意義不亞於React,但是React光芒太強。它能解決複雜資料在deepClone和對比過程中效能損耗。
注意:shouldComponentUpdate在初始化渲染的時候不會調用,但是在使用forceUpdate方法強制更新的時候也不會調用。
render
PureRenderMixin和shouldComponentUpdate的關注點是UI需不需要更新,而render則更多關注虛擬DOM的diff規則了,如何讓diff結果最小化、過程最簡化是render內最佳化的關注點。
React在進行虛擬DOM diff的時候假設:
1、擁有相同類的兩個組件將會產生相似的樹形結構,擁有不同類的兩個組件將會產生不同的樹形結構。
2、可以為元素提供一個唯一的標誌,該元素在不同的渲染過程中保持不變。
DOM結構
renderA: <div />renderB: <span />=> [removeNode <div />], [insertNode <span />
DOM屬性
renderA: <div id="before" />renderB: <div id="after" />=> [replaceAttribute id "after"]
之前插入DOM
renderA: <div><span>first</span></div>renderB: <div><span>second</span><span>first</span></div>=> [replaceAttribute textContent ‘second‘], [insertNode <span>first</span>]
之前插入DOM,有key的情況
renderA: <div><span key="first">first</span></div>renderB: <div><span key="second">second</span><span key="first">first</span></div>=> [insertNode <span>second</span>]
由於依賴於兩個預判條件,如果這兩個條件都沒有滿足,效能將會大打折扣。
1、diff演算法將不會嘗試匹配不同組件類的子樹。如果發現正在使用的兩個組件類輸出的 DOM 結構非常相似,你可以把這兩個組件類改成一個組件類。
2、如果沒有提供穩定的key(例如通過 Math.random() 產生),所有子樹將會在每次資料更新中重新渲染。
總結
使用PureRenderMixin、shouldComponentUpdate來避免不必要的虛擬DOM diff,在render內部最佳化虛擬DOM的diff速度,以及讓diff結果最小化。
使用immutable.js解決複雜資料diff、clone等問題。
React組件效能最佳化