React Diff:前端
每一個類型的元素更新處理方式:算法
瀏覽器基本元素的更新,分爲兩塊:segmentfault
一、 若是爲更新文本類型,內容不一樣就直接更新替換,並不會調用複雜的Diff算法:數組
ReactDOMTextComponent.prototype.receiveComponent(nextText, transaction) { //與以前保存的字符串比較 if (nextText !== this._currentElement) { this._currentElement = nextText; var nextStringText = '' + nextText; if (nextStringText !== this._stringText) { this._stringText = nextStringText; var commentNodes = this.getHostNode(); // 替換文本元素 DOMChildrenOperations.replaceDelimitedText( commentNodes[0], commentNodes[1], nextStringText ); } } }
二、對於自定義組件元素:瀏覽器
class Tab extends Component { constructor(props) { super(props); this.state = { index: 1, } } shouldComponentUpdate() { .... } render() { return ( <div> <p>item1</p> <p>item1</p> </div> ) } }
三、基本元素:dom
ReactDOMComponent.prototype.receiveComponent = function(nextElement, transaction, context) { var prevElement = this._currentElement; this._currentElement = nextElement; this.updateComponent(transaction, prevElement, nextElement, context); } ReactDOMComponent.prototype.updateComponent = function(transaction, prevElement, nextElement, context) { //須要單獨的更新屬性 this._updateDOMProperties(lastProps, nextProps, transaction, isCustomComponentTag); //再更新子節點 this._updateDOMChildren( lastProps, nextProps, transaction, context ); // ...... }
_updateChildren: function(nextNestedChildrenElements, transaction, context) { var prevChildren = this._renderedChildren; var removedNodes = {}; var mountImages = []; // 獲取新的子元素數組 var nextChildren = this._reconcilerUpdateChildren( prevChildren, nextNestedChildrenElements, mountImages, removedNodes, transaction, context ); if (!nextChildren && !prevChildren) { return; } var updates = null; var name; var nextIndex = 0; var lastIndex = 0; var nextMountIndex = 0; var lastPlacedNode = null; for (name in nextChildren) { if (!nextChildren.hasOwnProperty(name)) { continue; } var prevChild = prevChildren && prevChildren[name]; var nextChild = nextChildren[name]; if (prevChild === nextChild) { // 同一個引用,說明是使用的同一個component,因此咱們須要作移動的操做 // 移動已有的子節點 // NOTICE:這裏根據nextIndex, lastIndex決定是否移動 updates = enqueue( updates, this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex) ); // 更新lastIndex lastIndex = Math.max(prevChild._mountIndex, lastIndex); // 更新component的.mountIndex屬性 prevChild._mountIndex = nextIndex; } else { if (prevChild) { // 更新lastIndex lastIndex = Math.max(prevChild._mountIndex, lastIndex); } // 添加新的子節點在指定的位置上 updates = enqueue( updates, this._mountChildAtIndex( nextChild, mountImages[nextMountIndex], lastPlacedNode, nextIndex, transaction, context ) ); nextMountIndex++; } // 更新nextIndex nextIndex++; lastPlacedNode = ReactReconciler.getHostNode(nextChild); } // 移除掉不存在的舊子節點,和舊子節點和新子節點不一樣的舊子節點 for (name in removedNodes) { if (removedNodes.hasOwnProperty(name)) { updates = enqueue( updates, this._unmountChild(prevChildren[name], removedNodes[name]) ); } } }
基於tree diff:函數
基於component diff:性能
基於element diff:學習
「積跬步、行千里」—— 持續更新中~,喜歡留下個贊哦!
往期經典好文:優化
相關專欄推薦: