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() 主要做了三件事:
- 將 config 里的內(nèi)容復制作為 React 元素的 props献联。
- 處理 children,全部掛載到 props 的 children 屬性上何址。若只有一個參數(shù)里逆,則直接賦值給 children。
- 如果某個 prop 為空且存在默認的 prop, 將默認 prop 賦值給當前 prop用爪。
最后原押,返回 ReactElement 實例對象: return ReactElement(type, props, key, ref...)
2、React組件的創(chuàng)建
使用React創(chuàng)建組件時偎血,會調(diào)用 instantiateReactComponent(), 這是初始化組件的入口函數(shù)诸衔。他會根據(jù) node 類型來區(qū)分不同組件的入口盯漂。主要有一下幾種情況:
- node為空,表明node不存在笨农,則初始化空組件就缆。
- node為對象,表明是 DOM 標簽組件 (ReactDOMComponent)或自定義組件 (ReactCompositeComponent)谒亦。如果node.type === 'string' 竭宰,則初始化 DOM 標簽組件,否則初始化自定義組件份招。
- node為字符串或數(shù)字切揭,初始化 文本組件。
- 其他情況锁摔,不作處理廓旬。
3、文本組件
當node為文本節(jié)點時谐腰,不算 Virtual DOM 元素孕豹。但為了保持渲染的一致性,React將其封裝為文本組件 ReactDOMTextComponent十气。
在執(zhí)行 mountComponent 方法時巩步,ReactDOMTextComponent 會判斷該文本是否是通過 createElement 方法創(chuàng)建的節(jié)點。如果是桦踊,則為其創(chuàng)建相應的標簽及標識 domID,這樣每個文本節(jié)點也能和其他 React 節(jié)點一樣擁有唯一標識;如果不是终畅,就直接返回文本內(nèi)容籍胯。
文本內(nèi)容的更新則在 receiveComponent(nextComponent, transaction) 方法中執(zhí)行。
4离福、DOM標簽組件
ReactDOMComponent 針對 Virtual DOM 標簽的處理主要是兩部分:
- 屬性的更新杖狼。包括樣式、屬性妖爷、處理事件等蝶涩。
- 子節(jié)點的更新,包括內(nèi)容絮识、子節(jié)點绿聘。
4.1、更新屬性
在執(zhí)行 mountComponent 方法時次舌, ReactDOMComponent首先會生成標記和標簽熄攘,并對 DOM 節(jié)點的屬性和事件進行處理。包括以下幾點:
- 如果存在事件彼念,則為當前節(jié)點添加事件代理挪圾。
- 如果存在樣式浅萧,對樣式進行合并,然后創(chuàng)建樣式哲思。
- 創(chuàng)建屬性
- 創(chuàng)建唯一標識
當執(zhí)行 receiveComponent方法時洼畅,會對屬性進行更新,主要是:
- 刪除不需要的舊屬性棚赔。
- 更新新屬性帝簇。
4.1、更新子節(jié)點
在執(zhí)行 mountComponent 方法時忆嗜,會獲取節(jié)點內(nèi)容 props.dangerouslySetInnerHTML己儒。如果存在子節(jié)點,則對子節(jié)點進行初始化渲染捆毫。
當執(zhí)行 receiveComponent方法時闪湾,會對DOM內(nèi)容及子節(jié)點進行更新:
- 刪除不需要的子節(jié)點和內(nèi)容。
- 更新子節(jié)點和內(nèi)容绩卤。
5途样、自定義組件
ReactCompositeComponent自定義組件實現(xiàn)了一套React生命周期和setState機制,因此自定義組件是在生命周期的環(huán)境中進行更新屬性濒憋、內(nèi)容和子節(jié)點的操作何暇。這些操作與ReactDOMComponent的操作類似。