React 的最小實現 Kut

2021-09-13 23:03:42 字數 1764 閱讀 2595

kut,乙個簡單的react-like的前端檢視渲染庫,是我在學習react原始碼時造的輪子。kut是基於typescript的react最小實現。目前kut支援的top-level方法僅有兩個,即createelement、render,同時也支援元件化開發,demo在這裡。

原始碼都在src目錄下,目前一共9個檔案,分別如下。

定義了component類,以用於自定義元件,只是定義了一些屬性和方法,與react的component類似。

element是用於構造virtual dom節點的物件,element.ts中包含乙個工廠函式createelement。element有3個屬性:type是型別,可以是dom tag(如div等)或自定義元件(即component子類);key用於diff時對節點進行唯一區分;children是子節點陣列,其元素可以是文字或者element,和react的區別是,如果children只有一項時,kut的children仍是陣列,不過只有一項。

instance.ts中包含了三種不同型別element對應的例項類instance,對應reactcomponent(注意區別component,為避免混淆,kut中命名為instance),分別為文字例項textinstance、dom節點例項dominstance和自定義元件例項componentinstance。三種instance類結構基本類似,首先包含其對應於dom節點的唯一kutid,以方便進行掛載、更新和解除安裝;而index只用於列表項沒指定key時使用,可忽略;key和node用於獲取dom節點的key和節點本身。

instance的價值主要在於mount、shouldreceive、update和unmount方法。mount方法用於遍歷vdom樹,拼接html和新增監聽函式。而shouldreceive用於判斷是否為同一節點,若element的type和key相同,則直接呼叫update更新,否則呼叫unmount解除安裝並重新mount掛載。update方法則遞迴更新以當前節點為根節點的vdom子樹,其中若children大於一項的,會使用diff演算法計算其差異並呼叫patch進行更新。最後,unmount方法則從dom樹上解除安裝節點,並清除引用。

對於列表項更新,需要使用diff演算法計算其差異。react的實現可以參考這篇文章,我稱其為前向diff。kut基本的實現邏輯和react是相似的,但對於把元素從列表中底部挪到頂部的做法,react的前向diff會導致dom更新操作過多。kut的做法是引入後向diff,邏輯是和前向diff一致,只是方向相反,時間複雜度仍為o(n)。取前向diff和後向diff的更新操作較少者,呼叫patch函式對dom進行更新。這部分解釋我都寫在了diff.ts的注釋裡了。

分別是入口檔案、渲染方法、一些常量和一些工具函式。其中renderer.ts中定義了element例項化instantiate函式(即由element生成instance)和render函式(使用innerhtml進行掛載),由於採用innerhtml方法進行掛載,需要使用事件委託來處理事件,也需要使用dom節點唯一kutid進行區別,具體見event.ts。

react為保證相容性,具有合成事件。而kut為簡單起見,仍使用原生事件,採用事件委託的方式,將所有監聽函式掛在document上。event.ts的做法參考了的做法,實現了在document上新增和刪除監聽函式的方法,並以kutid判斷觸發的節點。

最近忙著實習面試和**暫時也沒太多時間加新功能,現在仍然有些bug,如componentdidmount的觸發時機不對。慢慢先打算支援非同步更新和context,起碼讓redux能用對吧,先寫篇記錄免得後頭來看連自己都忘了(苦笑)。推薦個最近看到的關於react原始碼的專欄,感覺講得還不錯的,在這裡:程式設計小思。

react 高階元件的實現

由於強大的mixin功能,在react元件開發過程中存在眾多不理於元件維護的因素,所以react社群提出了新的方法來替換mixin,那就是高階元件 首先在工程中安裝高階元件所需的依賴 npm install babel plugin proposal decorators然後輸入命令npm ejec...

最小堆的實現

這邊實現的是最小堆,最小堆是這樣定義的,首先堆是一棵完全二叉樹,每乙個節點都有乙個權值,滿足的條件是,父節點的權值總是大於等於子節點的權值 include using namespace std 最小堆類的定義如下 template class minheap template void minhe...

最小棧的實現

最小棧的實現 定義兩個棧,乙個資料棧,乙個最小棧 如果最小棧為空就直接把number壓人棧中 最小棧不為空,就把number與最小棧的棧頂元素進行比較,如果小於最小棧的棧頂元素,就把number壓入最小棧,否則就把number壓入datastack中,最後返回最小棧的棧頂元素就是最小值 includ...