Kut,一個簡單的React-Like的前端視圖渲染庫,是我在學習React源碼時造的輪子。Kut是基於Typescript的React最小實現。目前Kut支持的Top-Level方法僅有兩個,即createElement、render,同時也支持組件化開發,Demo在這裏。前端
本文主要對Kut的源碼進行說明和記錄,項目地址:Github。node
源碼都在src
目錄下,目前一共9個文件,分別以下。git
定義了Component類,以用於自定義組件,只是定義了一些屬性和方法,與React的Component相似。github
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樹上卸載節點,並清除引用。npm
對於列表項更新,須要使用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源碼的專欄,感受講得還不錯的,在這裏:編程小思。
歡迎pr和stars,項目地址:Github。