React源碼解讀之Virtual DOM

Virtual DOM 相當于一個虛擬空間,React 的所有工作幾乎都是基于 Virtual DOM 完成的,包括虛擬節(jié)點及其屬性的構建、更新、刪除等工作。Virtual DOM 需要具備一個DOM標簽所需的基本元素:標簽名、節(jié)點屬性(樣式、屬性、事件等)、子節(jié)點、標識id,示例如下

{
    tagName: '',
    properties: { style: {} },
    children:[],
    key: '',
}

Virtual DOM 中的節(jié)點被稱為 ReactNode, 分為三種類型:ReactElement、ReactFragment 和 ReactText。其中,ReactElement 又分為 ReactDOMElement和 ReactComponentElement。不同類型節(jié)點的基礎元素有所不同。

1、React元素的創(chuàng)建

React 元素的創(chuàng)建是通過 createElement(type, config, children) 方法。type 表示創(chuàng)建什么類型的DOM元素,config 聲明屬性列表,children 為子元素。本方法可接受多個參數(shù),第三個至第N個都被當做子元素處理。

createElement() 主要做了三件事:

  1. 將 config 里的內容復制作為 React 元素的 props。
  2. 處理 children,全部掛載到 props 的 children 屬性上。若只有一個參數(shù),則直接賦值給 children。
  3. 如果某個 prop 為空且存在默認的 prop, 將默認 prop 賦值給當前 prop。
    最后,返回 ReactElement 實例對象: return ReactElement(type, props, key, ref...)
2、React組件的創(chuàng)建

使用React創(chuàng)建組件時,會調用 instantiateReactComponent(), 這是初始化組件的入口函數(shù)。他會根據 node 類型來區(qū)分不同組件的入口。主要有一下幾種情況:

  1. node為空,表明node不存在,則初始化空組件。
  2. node為對象,表明是 DOM 標簽組件 (ReactDOMComponent)或自定義組件 (ReactCompositeComponent)。如果node.type === 'string' ,則初始化 DOM 標簽組件,否則初始化自定義組件。
  3. node為字符串或數(shù)字,初始化 文本組件
  4. 其他情況,不作處理。
3、文本組件

當node為文本節(jié)點時,不算 Virtual DOM 元素。但為了保持渲染的一致性,React將其封裝為文本組件 ReactDOMTextComponent。

在執(zhí)行 mountComponent 方法時,ReactDOMTextComponent 會判斷該文本是否是通過 createElement 方法創(chuàng)建的節(jié)點。如果是,則為其創(chuàng)建相應的標簽及標識 domID,這樣每個文本節(jié)點也能和其他 React 節(jié)點一樣擁有唯一標識;如果不是,就直接返回文本內容。

文本內容的更新則在 receiveComponent(nextComponent, transaction) 方法中執(zhí)行。

4、DOM標簽組件

ReactDOMComponent 針對 Virtual DOM 標簽的處理主要是兩部分:

  • 屬性的更新。包括樣式、屬性、處理事件等。
  • 子節(jié)點的更新,包括內容、子節(jié)點。
4.1、更新屬性

在執(zhí)行 mountComponent 方法時, ReactDOMComponent首先會生成標記和標簽,并對 DOM 節(jié)點的屬性和事件進行處理。包括以下幾點:

  • 如果存在事件,則為當前節(jié)點添加事件代理。
  • 如果存在樣式,對樣式進行合并,然后創(chuàng)建樣式。
  • 創(chuàng)建屬性
  • 創(chuàng)建唯一標識

當執(zhí)行 receiveComponent方法時,會對屬性進行更新,主要是:

  1. 刪除不需要的舊屬性。
  2. 更新新屬性。
4.1、更新子節(jié)點

在執(zhí)行 mountComponent 方法時,會獲取節(jié)點內容 props.dangerouslySetInnerHTML。如果存在子節(jié)點,則對子節(jié)點進行初始化渲染。

當執(zhí)行 receiveComponent方法時,會對DOM內容及子節(jié)點進行更新:

  • 刪除不需要的子節(jié)點和內容。
  • 更新子節(jié)點和內容。
5、自定義組件

ReactCompositeComponent自定義組件實現(xiàn)了一套React生命周期和setState機制,因此自定義組件是在生命周期的環(huán)境中進行更新屬性、內容和子節(jié)點的操作。這些操作與ReactDOMComponent的操作類似。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容