【Under-the-hood-ReactJS-Part0】React源碼解讀

接上文---html

完整流程圖見:https://bogdan-lyashenko.gith...
繼續咱們的React之旅,讓咱們從ReactDOM.render的調用開始。git

ReactDOM.render

ReactDOM.render是咱們分析的入口點。咱們的應用從這裏開始渲染內容到DOM樹中。爲了方便調試,咱們建立了一個<ExampleApplication/>的簡單組件。整個流程的第一個動做就是把JSX轉換成React elements 。 React elements就是帶一些架構的簡單對象。 他們就是用來表示組件render方法的返回值,除此以外,沒有其餘的。對象中的一些字段,如props,key,ref對於你們應該已經很熟悉了。 type屬性表示的是JSX定義的標記對象,在咱們的案例中,就是類 ExampleApplication, 固然,它也能夠表示 Button標籤的字符串格式等等。 同時,在React element的建立期間,React將會合並defaultProps和props(若是有聲明的話),而且嚴重propTypes。
更多詳情請查看源碼 srcisomorphicclassicelementReactElement.jsgithub

ReactMount

在流程圖中,你能夠發現有個叫作ReactMount的模塊。它包含了整個組件掛載的邏輯。
其實,ReactDOM中是沒有任何邏輯的,它不過是一個用來調用ReactMount的接口,因此當調用ReactDOM.render方法時,技術上來講,你真正調用的是ReactMount.render方法。那麼整個掛載過程究竟是怎麼樣的呢?緩存

Mounting is the process of initializing a React component by creating its representative DOM elements and inserting them into a supplied container.(掛載是指初始化一個React組件的過程,包括生成組件對應的DOM元素並插入指定的容器中)

以上文字來自於React代碼的註釋,那麼這些究竟是一個怎麼樣的過程呢?咱們先看下如下的一個轉化:
React須要將你組件裏的JSX描述轉化爲對應的HTML結構,並插入到DOM樹中,這個過程,
React須要處理全部的屬性,綁定的事件,內嵌的組件和全部邏輯。掛載,就是指把用高層次語言描述的組件(JSX)轉化爲低層次的html代碼,而後插入到DOM樹中。架構

爲了讓以上描述更具體下,考慮以下需求:app

目標:確保滾動事件被監聽
在一個根組件的第一次渲染過程當中,React會初始化滾動監聽事件,而且把滾動條相關數值緩存起來,這樣,當應用代碼能夠在不觸發重排(reflow)的前提下,訪問到滾動條相關數據。因爲不一樣的遊覽器會有不一樣的實現,一些DOM的數值是非固定的,每次當你在代碼中獲取它們時,它們都有可能會從新計算。顯然,這一步驟會引發一些性能問題。好比,一些老的遊覽器,是不支持pageX和pageY屬性的。爲了解決這個問題,React會作一些優化,而這些優化過程當中,可能就會須要不少其它技巧。在其它問題中,React爲了解決某個具體的問題,都會用到不少技巧,滾動條就是一個具體的列子。

實例化React組件

回顧下最開始的流程圖,這裏有一個實例建立的過程。事實上,目前去建立一個<ExampleApplication>的實例還有點早,這裏咱們真正實例化的是類TopLevelWrapper(React內部類)。咱們先跳過這個過程,看下一個流程。dom

在JSX的轉化過程當中,這裏有三個階段。JSX轉化成React elements後,React elements會被轉化爲如下內部React組件類型中的一:ReactCompositeComponent(開發自定義的組件),ReactDOMComponent(HTML DOM節點),ReactDOMTextComponent(文本節點)。咱們先忽略ReactDOMTextComponent,重點放在前兩個。svg

什麼是內部組件呢?你可能已經聽過虛擬DOM。虛擬DOM是一種DOM的表示方式,在React的diff差別計算以及其它過程當中,使用虛擬DOM使得能夠不直接DOM樹,而這恰是React性能不錯的緣由之一。其實,在React的源碼中,並無什麼文件或者類被稱做虛擬DOM,由於虛擬DOM只是一種概念,一種用來描述如何處理真實DOM的手段。有些人可能會說虛擬DOM表示的就是React elements,可是我不這麼認爲。在我看來,虛擬DOM指的是這三個類:ReactCompositeComponent,ReactDOMComponent,ReactDOMTextComponent。稍後我會詳細解釋緣由。性能

讓咱們繼續組件的實例化。咱們會建立一個ReactCompositeComponent的實例,可是,
這個實例並非由於咱們將<ExampleApplication/>放入ReactDOM.render中而後才生成的。React老是從TopLevelWrapper裏開始渲染一個組件樹。它幾乎是一個純包裝組件,它的render方法(組件的render方法)將會返回<ExampleApplication/>。代碼以下:優化

//src\renderers\dom\client\ReactMount.js#277
TopLevelWrapper.prototype.render = function () {
  return this.props.child;
};

根據以上代碼,很顯然只有一個TopLevelWrapper的實例被建立了,除此以外就沒有其它的了。在繼續下一步以前,咱們看下如下內容:

DOM內嵌驗證
幾乎每次內嵌組件渲染時,它們都會被一個專門用來作HTML驗證的模塊--validateDOMNesting--來驗證結構是否合法。所謂的DOM內嵌驗證是指校驗子模塊和父模塊的標籤層次。好比,若是父組件的標籤是<select>,子組件的標籤只能是如下中的一個:optino,optgroup,#text。 這些規則都是在 https://html.spec.whatwg.org/... 被定義的。你極可能已經看到過這個模塊的工做成果,它會產生以下的錯誤提醒:<div>不能爲<p>的後代出現(<div> cannot appear as a descendant of <p> .)

好了,讓咱們回想下以前的內容,而後再回顧下掛載相關的流程圖。 Part0的部分就是這些。

(未完待續)

相關文章
相關標籤/搜索