国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React學習之解讀React源碼

developerworks / 2047人閱讀

摘要:根據的類型不同,分別實例化類。并且處理特殊屬性,比如事件綁定。之后根據差異對象操作元素位置變動,刪除,添加等。各個組件獨立管理層層嵌套,互不影響,內部實現的渲染功能。根據基本元素的值,判斷是否遞歸更新子節點,還是刪除舊節點,添加新節點。

首先理解ReactElement和ReactClass的概念。想要更好的利用react的虛擬DOM,diff算法的優勢,我們需要正確的優化、組織react頁面。

理解ReactElement和ReactClass的概念

ReactElement

一個描述DOM節點或component實例的字面級對象。它包含一些信息,包括組件類型type和屬性props。就像一個描述DOM節點的元素(虛擬節點)。它們可以被創建通過React.createElement方法或jsx寫法
分為DOM Element和Component Elements兩類:

DOM Elements

當節點的type屬性為字符串時,它代表是普通的節點,如div,span

{ 
type: "button", 
  props: { 
    className: "button button-blue", 
    children: { 
      type: "b", 
      props: { 
        children: "OK!" 
      } 
    } 
  } 
}  

Component Elements

當節點的type屬性為一個函數或一個類時,它代表自定義的節點

class Button extends React.Component { 
  render() { 
    const { children, color } = this.props; 
    return { 
      type: "button", 
      props: { 
        className: "button button-" + color, 
        children: { 
          type: "b", 
          props: { 
           children: children 
          } 
        } 
      } 
    }; 
  } 
} 
 
// Component Elements 
{ 
 type: Button, 
  props: { 
    color: "blue", 
    children: "OK!" 
  } 
}  
ReactElement

ReactClass是平時我們寫的Component組件(類或函數),例如上面的Button類。ReactClass實例化后調用render方法可返回DOM Element。

react渲染過程

過程理解:

// element是 Component Elements 
ReactDOM.render({ 
  type: Form, 
  props: { 
    isSubmitted: false, 
    buttonText: "OK!" 
  } 
}, document.getElementById("root"));

調用React.render方法,將我們的element根虛擬節點渲染到container元素中。element可以是一個字符串文本元素,也可以是如上介紹的ReactElement(分為DOM Elements, Component Elements)。

根據element的類型不同,分別實例化ReactDOMTextComponent, ReactDOMComponent, ReactCompositeComponent類。這些類用來管理ReactElement,負責將不同的ReactElement轉化成DOM(mountComponent方法),負責更新DOM(receiveComponent方法,updateComponent方法, 如下會介紹)等。

ReactCompositeComponent實例調用mountComponent方法后內部調用render方法,返回了DOM Elements。

react更新機制

每個類型的元素都要處理好自己的更新:


自定義元素的更新,主要是更新render出的節點,做甩手掌柜交給render出的節點的對應component去管理更新。

text節點的更新很簡單,直接更新文案。

瀏覽器基本元素的更新,分為兩塊:

先是更新屬性,對比出前后屬性的不同,局部更新。并且處理特殊屬性,比如事件綁定。

然后是子節點的更新,子節點更新主要是找出差異對象,找差異對象的時候也會使用上面的shouldUpdateReactComponent來判斷,如果是可以直接更新的就會遞歸調用子節點的更新,這樣也會遞歸查找差異對象。不可直接更新的刪除之前的對象或添加新的對象。之后根據差異對象操作dom元素(位置變動,刪除,添加等)。

第一步:調用this.setState
ReactClass.prototype.setState = function(newState) { 
    //this._reactInternalInstance是ReactCompositeComponent的實例 
    this._reactInternalInstance.receiveComponent(null, newState); 
}  
第二步:調用內部receiveComponent方法

這里主要分三種情況,文本元素,基本元素,自定義元素。
自定義元素:
receiveComponent方法源碼:

// receiveComponent方法 
ReactCompositeComponent.prototype.receiveComponent = function(nextElement, transaction, nextContext) { 
    var prevElement = this._currentElement; 
    var prevContext = this._context; 
 
    this._pendingElement = null; 
 
    this.updateComponent( 
      transaction, 
      prevElement, 
      nextElement, 
      prevContext, 
      nextContext 
    ); 
 
}  

updateComponent方法源碼

// updateComponent方法 
ReactCompositeComponent.prototype.updateComponent = function( 
   transaction, 
   prevParentElement, 
   nextParentElement, 
   prevUnmaskedContext, 
   nextUnmaskedContext 
) { 
   // 簡寫..... 
    
    // 不是state更新而是props更新 
    if (prevParentElement !== nextParentElement) { 
      willReceive = true; 
    } 
 
    if (willReceive && inst.componentWillReceiveProps) { 
        // 調用生命周期componentWillReceiveProps方法 
    } 
     
    // 是否更新元素 
    if (inst.shouldComponentUpdate) { 
        // 如果提供shouldComponentUpdate方法 
        shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext); 
    } else { 
        if (this._compositeType === CompositeTypes.PureClass) { 
          // 如果是PureClass,淺層對比props和state 
          shouldUpdate = 
            !shallowEqual(prevProps, nextProps) || 
            !shallowEqual(inst.state, nextState); 
        } 
    } 
     
    if (shouldUpdate) { 
      // 更新元素 
      this._performComponentUpdate( 
        nextParentElement, 
        nextProps, 
        nextState, 
        nextContext, 
        transaction, 
        nextUnmaskedContext 
      ); 
    } else { 
      // 不更新元素,但仍然設置props和state 
      this._currentElement = nextParentElement; 
      this._context = nextUnmaskedContext; 
      inst.props = nextProps; 
      inst.state = nextState; 
      inst.context = nextContext; 
    } 
        
   // ....... 
 
}  

內部_performComponentUpdate方法源碼

function shouldUpdateReactComponent(prevElement, nextElement){ 
  var prevEmpty = prevElement === null || prevElement === false; 
  var nextEmpty = nextElement === null || nextElement === false; 
 if (prevEmpty || nextEmpty) { 
    return prevEmpty === nextEmpty; 
  } 
 
  var prevType = typeof prevElement; 
  var nextType = typeof nextElement; 
   
  if (prevType === "string" || prevType === "number") { 
    // 如果先前的ReactElement對象類型是字符串或數字,新的ReactElement對象類型也是字符串或數字,
    return (nextType === "string" || nextType === "number"); 
  } else { 
      // 如果先前的ReactElement對象類型是對象,新的ReactElement對象類型也是對象,并且標簽類型和key值相同,則需要更新 
     return ( 
       nextType === "object" && 
       prevElement.type === nextElement.type && 
       prevElement.key === nextElement.key 
     ); 
   } 
 }

基本元素
receiveComponent方法源碼

ReactDOMComponent.prototype.receiveComponent = function(nextElement, transaction, context) { 
   var prevElement = this._currentElement; 
     this._currentElement = nextElement; 
    this.updateComponent(transaction, prevElement, nextElement, context); 
}  

updateComponent方法源碼

ReactDOMComponent.prototype.updateComponent = function(transaction, prevElement, nextElement, context) { 
    // 略..... 
    //需要多帶帶的更新屬性 
    this._updateDOMProperties(lastProps, nextProps, transaction, isCustomComponentTag); 
    //再更新子節點 
    this._updateDOMChildren( 
      lastProps, 
      nextProps, 
      transaction, 
      context 
    ); 
 
    // ...... 
}  

this._updateDOMChildren方法內部調用diff算法。

react Diff算法

diff算法源碼

_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]) 
        ); 
      } 
    } 
  }  
react的優點與總結 優點:

虛擬節點。在UI方面,不需要立刻更新視圖,而是生成虛擬DOM后統一渲染。

組件機制。各個組件獨立管理,層層嵌套,互不影響,react內部實現的渲染功能。

差異算法。根據基本元素的key值,判斷是否遞歸更新子節點,還是刪除舊節點,添加新節點。

總結:

想要更好的利用react的虛擬DOM,diff算法的優勢,我們需要正確的優化、組織react頁面。例如將一個頁面render的ReactElement節點分解成多個組件。在需要優化的組件手動添加 shouldComponentUpdate 來避免不需要的 re-render。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105570.html

相關文章

  • 【搶先領】《React 習之道》我們翻譯了一本最簡單,且最實用的 React 實戰教程……

    摘要:學習之道簡體中文版通往實戰大師之旅掌握最簡單,且最實用的教程。前言學習之道這本書使用路線圖中的精華部分用于傳授,并將其融入一個獨具吸引力的真實世界的具體代碼實現。完美展現了的優雅。膜拜的學習之道是必讀的一本書。 《React 學習之道》The Road to learn React (簡體中文版) 通往 React 實戰大師之旅:掌握 React 最簡單,且最實用的教程。 showIm...

    oneasp 評論0 收藏0
  • GraphQL習之實踐篇

    摘要:前言兩篇文章學完了基礎篇原理篇,接下去便是實踐的過程,這個實踐我們使用了如下技術棧去實現一套任務管理系統,源碼就不公開了等穩定后再發布。后續我所在的公司網關團隊會持續實踐,爭取貢獻出更多的解決方案。前言 兩篇文章學完了GraphQL(基礎篇, 原理篇),接下去便是實踐的過程,這個實踐我們使用了如下技術棧去實現一套任務管理系統,源碼就不公開了, 等穩定后再發布。效果如下: showImg(ht...

    Drinkey 評論0 收藏0
  • React習之深入Redux應用框架

    摘要:作為大型應用狀態管理最常用的工具。它是一個應用數據流框架,與框架類似。這是觸發變化的惟一途徑。在這個函數內部,被調用,其作用是監測是的。否則的話,認為只是一個普通的,將通過也就是進一步分發。到此源碼的主要部分學習結束。 Redux作為大型React應用狀態管理最常用的工具。它是一個應用數據流框架,與Flux框架類似。它是零依賴的,可以配合其他框架或者類庫一起使用。雖然在平時的工作中很多...

    張漢慶 評論0 收藏0
  • React習之初入React世界

    摘要:語法將語法直接加入到代碼中,再通過翻譯器裝換到純后由瀏覽器執行。事實上,并不需要花精力學習。可以說,基本語法基本被囊括了,但也有少許不同。明確的數據流動。這條原則讓組件之間的關系變得簡單且可預測。使用獲取和顯示回調。 JSX語法 JSX將HTML語法直接加入到JavaScript代碼中,再通過翻譯器裝換到純JavaScript后由瀏覽器執行。在實際開發中,JSX在產品打包階段都已經編...

    cjie 評論0 收藏0
  • React習之認識Flux架構模式

    摘要:是用戶建立客戶端應用的前端架構,它通過利用一個單向的數據流補充了的組合視圖組件,這更是一種模式而非正式框架,你能夠無需許多新代碼情況下立即開始使用。結構和數據流一個單向數據流是模式的核心。 Flux是Facebook用戶建立客戶端Web應用的前端架構,它通過利用一個單向的數據流補充了React的組合視圖組件,這更是一種模式而非正式框架,你能夠無需許多新代碼情況下立即開始使用Flux。 ...

    EasonTyler 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<