摘要:我們需要一個帶有入?yún)⒑头椒ǖ臉嬙旌瘮?shù),方法可以接收作為入?yún)砀陆M件狀態(tài)我們在創(chuàng)建組件時都會繼承上面這個類。我們需要一個方法能根據(jù)傳入的元素來創(chuàng)建組件的實例稱之為公共實例,其實就是根據(jù)這個構造函數(shù)出來的一個對象。
翻譯自:https://engineering.hexacta.c...
上一節(jié)的代碼有一些問題:
每次更新都會帶來整顆虛擬DOM樹的一致性校驗;
狀態(tài)是全局的(沒有私有狀態(tài));
有變化發(fā)生后必須手動調用render方法以便將變化反應到頁面上。
組件可以幫我們解決上面的問題,同時還能帶來一些新特性:
允許自定義JSX的標簽名
生命周期鉤子(這一節(jié)暫不介紹這部分)
首先我們要定義一個Component的基礎類,在創(chuàng)建其它組件時都要繼承該類。我們需要一個帶有props入?yún)⒑?b>setState方法的構造函數(shù),setState方法可以接收partialState作為入?yún)砀陆M件狀態(tài):
class Component{ constructor(props){ this.props = props; this.state = this.state || {} } setState(partialState){ this.state = Object.assign({}, this.state, partialState); } }
我們在創(chuàng)建組件時都會繼承上面這個類。組件的使用方法和原生的標簽如div或者span一樣,直接像這樣
function createPublicInstance(element, internalInstance){ const {type, props} = element; const publicInstance = new type(props); // 這地方的type對應組件的構造函數(shù) publicInstance.__internalInstance = internalInstance; return publicInstance; }
組件的內部實例含有組件對應的dom元素(內部實例就是前幾節(jié)我們說的實例,通過調用instantiate方法生成的)。公共實例與內部實例的引用關系會被保存著,通過這個引用關系可以找到公共實例對應的內部實例及虛擬DOM,當公共實例狀態(tài)發(fā)生變化時,我們就可以只更新發(fā)生變化的內部實例及其對應的那部分虛擬DOM:
class Component{ constructor(props){ this.props = props; this.state = this.state || {} } setState(partialState){ this.state = Object.assign({}, this.state, partialState); updateInstance(this.__internalInstance); } } function updateInstance(internalInstance){ const parentDom = internalInstance.dom.parentNode; const element = internalInstance.element; reconcile(parentDom, internalInstance, element); }
instantiate方法需要做一些改造。對組件來講,我們需要先創(chuàng)建公共實例(先new一個組建),然后調用組件的render方法來獲取組件內部的元素,最后把獲取到的元素傳遞給instantiate方法。
function instantiate(element){ const { type, props } = element; const isDomElement = typeof type === "string"; if(isDomElement){ // 如果是原生的dom元素的話,直接創(chuàng)建實例 const isTextElement = type === TEXT_ELEMENT; const dom = isTextElement ? document.createTextNode("") : document.createElement(type); updateDomProperties(dom, [], props); const childElements = props.children || []; const childInstances = childElements.map(instantiate); const childDoms = childInstances.map(childInstance => childInstance.dom); childDoms.forEach(childDom => dom.appendChild(childDom)); const instance = { dom, element, childInstances }; return instance; } else {// 否則先創(chuàng)建公共實例,然后再調用instantiate方法創(chuàng)建內部實例 const instance = {}; // 這地方的element是一個type屬性為一個構造函數(shù)的對象 const publicInstance = createPublicInstance(element, instance); const childElement = publicInstance.render(); const childInstance = instantiate(childElement); const dom = childInstance.dom; Object.assign(instance, { dom, element, childInstance, publicInstance}); return instance; } }
組件對應的內部實例和原生dom元素對應的實例有些不一樣。組件內部實例只會擁有一個子元素,即render方法返回的內容,而原生dom元素則可以含有多個子元素。所以對于組件內部實例來講,它們會有一個childInstance屬性而不是一個childInstances數(shù)組。此外,由于在進行一致性校驗時需要調用組件的render方法,所以組件內部實例會保存對公共實例的引用(反過來公共實例也保存著對內部實例的引用)。
接下來我們來處理下組件實例的一致性校驗。因為組件的內部實例只含有一個子元素(所有元素有一個統(tǒng)一的父類),只需要更新公共實例的props屬性,執(zhí)行render方法獲取子元素,然后再進行一致性校驗就可以了。
function reconcile(parentDom, instance, element){ if(instance == null){ const newInstance = instantiate(element); parentDom.appendChild(newInstance.dom); return newInstance; } else if( element == null){ parentDom.removeChild(instance.dom); return null; } else if(instance.element.type !== element.type){ const newInstance = instantiate(element); parentDom.replaceChild(newInstance.dom, instance.dom); return newInstance; } else if(typeof element.type === "string"){ updateDomProperties(instance.dom, instance.element, props, element.props); instance.childInstances = reconcileChildren(instance, element); instance.element = element; return instance; } else { instance.publicInstance.props = element.props;// 更新公共實例的props const childElement = instance.publicInstance.render(); // 獲取最新的子元素 const oldChildInstance = instance.childInstance; const childInstance = reconcile(parentDom, oldChildInstance, childElement); instance.dom = childInstance.dom; instance.childInstance = childInstance; instance.element = element; return instance; } }
現(xiàn)在,我們的Didact.js已經(jīng)可以支持組件了。這里可以在線編輯代碼并能看到效果。
使用組件后,我們可以創(chuàng)建自定義的JSX標簽,并擁有了組件內部狀態(tài),而且組件有變化時只會變更自己的那部分dom內容。
相關內容到此結束。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/99870.html
摘要:我們需要一個帶有入?yún)⒑头椒ǖ臉嬙旌瘮?shù),方法可以接收作為入?yún)砀陆M件狀態(tài)我們在創(chuàng)建組件時都會繼承上面這個類。我們需要一個方法能根據(jù)傳入的元素來創(chuàng)建組件的實例稱之為公共實例,其實就是根據(jù)這個構造函數(shù)出來的一個對象。 翻譯自:https://engineering.hexacta.c... 上一節(jié)的代碼有一些問題: 每次更新都會帶來整顆虛擬DOM樹的一致性校驗; 狀態(tài)是全局的(沒有私有狀...
摘要:,谷歌給的一份性能指南和最佳實踐。目前而言,前端社區(qū)有三大框架和。隨后重點講述了和兩大前端框架,給出了大量的文章教程和相關資源列表。我認為,使用函數(shù)式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個是我訂閱 陳皓老師在極客上的專欄《左耳聽風》...
摘要:,谷歌給的一份性能指南和最佳實踐。目前而言,前端社區(qū)有三大框架和。隨后重點講述了和兩大前端框架,給出了大量的文章教程和相關資源列表。我認為,使用函數(shù)式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個是我訂閱 陳皓老師在極客上的專欄《左耳聽風》...
摘要:將注意力集中保持在核心庫,而將其他功能如路由和全局狀態(tài)管理交給相關的庫。此示例使用類似的語法,稱為。執(zhí)行更快,因為它在編譯為代碼后進行了優(yōu)化?;诘哪0迨沟脤⒁延械膽弥鸩竭w移到更為容易。 前言 因為沒有明確的界定,這里不討論正確與否,只表達個人對前端MV*架構模式理解看法,再比較React和Vue兩種框架不同.寫完之后我知道這文章好水,特別是框架對比部分都是別人說爛的,而我也是打算把...
閱讀 649·2023-04-26 02:59
閱讀 758·2023-04-25 16:02
閱讀 2230·2021-08-05 09:55
閱讀 3703·2019-08-30 15:55
閱讀 4812·2019-08-30 15:44
閱讀 1852·2019-08-30 13:02
閱讀 2268·2019-08-29 16:57
閱讀 2347·2019-08-26 13:35