react更新渲染及渲染原理

2022-05-06 15:03:13 字數 3929 閱讀 2847

觸發元件的更新有兩種更新方式:props以及state改變帶來的更新。本次主要解析state改變帶來的更新。整個過程流程圖如下:

1、一般改變state,都是從setstate開始,這個函式被呼叫之後,會將我們傳入的state放進pendingstate的陣列裡存起來,然後判斷當前流程是否處於批量更新,如果是,則將當前元件的instance放進dirtycomponent裡,當這個更新流程中所有需要更新的元件收集完畢之後(這裡面涉及到事務的概念,感興趣的可以自己去了解一下)就會遍歷dirtycomponent這個陣列,呼叫他們的uptatecomponent對元件進行更新。當然,如果當前不處於批量更新的狀態,會直接去遍歷dirtycomponent進行更新。

計算出nextstate

render()得到nextrenderelement

與prevelement 進行diff 比較(這個過程後面會介紹),更新節點

最後這個需要去更新節點的時候,跟首次渲染一樣,也需要呼叫reactdomcomponent的updatecomponent來更新。其中第二步render得到的也是自定義元件的話, 會形成遞迴呼叫。

接下來,還是上次的問題:那麼更新過程中的生命週期函式,shouldcomponentupdate,componentwillupdate跟componentdidupdate在哪被呼叫呢?

由圖可知,shouldcomponentupdate在第一步呼叫得到nextstate之後呼叫,因為nextstate也是它的其中乙個引數嘛~這個函式很重要,它是我們效能優化的乙個很關鍵的點:由圖可以看到,當shouldcomponentupdate返回false的時候,下面的一大塊都不會被去執行,包括已經被優化的diff演算法。

當shouldcomponentupdate返回true的時候,會先呼叫componentwillupdate,在整個更新過程結束之後呼叫componentdidupdate。

以上就是更新渲染的過程。

react基於兩個假設:

兩個相同的元件產生類似的dom結構,不同元件產生不同dom結構

對於同一層次的一組子節點,它們可以通過唯一的id區分

發明了一種叫diff的演算法來比較兩棵dom tree,它極大的優化了這個比較的過程,將演算法複雜度從o(n^3)降低到o(n)。

同時,基於第一點假設,我們可以推論出,diff演算法只會對同層的節點進行比較。如圖,它只會對顏色相同的節點進行比較。

也就是說如果父節點不同,react將不會在去對比子節點。因為不同的元件dom結構會不相同,所以就沒有必要在去對比子節點了。這也提高了對比的效率。

下面,我們具體看下diff演算法是怎麼做的,這裡分為三種情況考慮

不同節點型別

對於不同的節點型別,react會基於第一條假設,直接刪去舊的節點,新建乙個新的節點。

比如:

// 由shape1到shape2

react會直接刪掉a節點(包括它所有的子節點),然後新建乙個b節點插入

- codesandboxlyop4w9x9m - codesandbox

最後終端輸出的結果是:

shape1 :

a is created

a render

c is created

c render

c componentdidmount

a componentdidmountshape2 :

a componentwillunmount

c componentwillunmount

b is created

b render

c is created

c render

c componentdidmount

b componentdidmount

由此可以看出,a與其子節點c會被直接刪除,然後重新建乙個b,c插入。這樣就給我們的效能優化提供了乙個思路,就是我們要保持dom標籤的穩定性

打個比方,如果寫了乙個

(list 是乙個有幾千個節點的元件),切換的時候變成了,此時即使list的內容不變,它也會先被解除安裝在建立,其實是很浪費的。

相同節點型別

當對比相同的節點型別比較簡單,這裡分為兩種情況,一種是dom元素型別,對應html直接支援的元素型別:div,span和p,還有一種是自定義元件。

比如:

這兩個div中,react會只更新classname的值

這兩個div中,react只會去更新color的值

- shouldcomponentupdate

- componentwillreceiveprops

- componentwillupdate

- render

- componentdidupdate

子節點比較

// 列表一到列表二

因為react在沒有key的情況下對比節點的時候,是乙個乙個按著順序對比的。從列表一到列表二,只是在中間插入了乙個c,但是如果沒有key的時候,react會把b刪去,新建乙個c放在b的位置,然後重新建乙個節點b放在尾部。

列表一:

a is created

a render

b is created

b render

a componentdidmount

b componentdidmount列表二:

a render

b componentwillunmount

c is created

c render

b is created

b render

a componentdidupdate

c componentdidmount

b componentdidmount

當節點很多的時候,這樣做是非常低效的。有兩種方法可以解決這個問題:

1、保持dom結構的穩定性,我們來看這個變化,由兩個子節點變成了三個,其實是乙個不穩定的dom結構,我們可以通過通過加乙個null,保持dom結構的穩定。這樣按照順序對比的時候,b就不會被解除安裝又重建回來。

// 列表一到列表二

2、key

通過給節點配置key,讓react可以識別節點是否存在。

配上key之後,在跑一遍**看看。

a render

c is created

c render

b render

a componentdidupdate

c componentdidmount

b componentdidupdate

果然,配上key之後,列表二的生命週期就如我所願,只在指定的位置建立c節點插入。

這裡要注意的一點是,key值必須是穩定(所以我們不能用math.random()去建立key),可**,並且唯一的。

這裡給我們效能優化也提供了兩個非常重要的依據:

react 渲染原理

一 jsx如何生成element 這裡是一段寫在render裡的jsx return hello,this is react start to learn right now right reserve.首先,它會經過babel編譯成react.createelement的表示式。return re...

react元件渲染原理

jsx 經過babel編譯成react.createelement的表示式。element在react裡,是組成虛擬dom 樹的節點,用來描述在瀏覽器上看到什麼。它的引數有三個 1 type 標籤 2 attributes 標籤屬性,沒有的話,可以為null 3 children 標籤的子節點 e....

React元件及渲染

首先來說一下什麼是react元件,它其實是頁面上的一部分,例如標題 搜尋框 按鈕等都可以是乙個元件。react的元件又分為函式元件 和class元件。函式元件定義可以如下 這是乙個函式元件,它的本質其實是j ascript函式。它接收唯一帶有資料的 props 代表屬性 物件與並返回乙個react元...