成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

構(gòu)建自己的React:(4)Components and State

cncoder / 1155人閱讀

摘要:我們需要一個(gè)帶有入?yún)⒑头椒ǖ臉?gòu)造函數(shù),方法可以接收作為入?yún)?lái)更新組件狀態(tài)我們?cè)趧?chuàng)建組件時(shí)都會(huì)繼承上面這個(gè)類。我們需要一個(gè)方法能根據(jù)傳入的元素來(lái)創(chuàng)建組件的實(shí)例稱之為公共實(shí)例,其實(shí)就是根據(jù)這個(gè)構(gòu)造函數(shù)出來(lái)的一個(gè)對(duì)象。

翻譯自:https://engineering.hexacta.c...

上一節(jié)的代碼有一些問(wèn)題:

每次更新都會(huì)帶來(lái)整顆虛擬DOM樹(shù)的一致性校驗(yàn);

狀態(tài)是全局的(沒(méi)有私有狀態(tài));

有變化發(fā)生后必須手動(dòng)調(diào)用render方法以便將變化反應(yīng)到頁(yè)面上。

組件可以幫我們解決上面的問(wèn)題,同時(shí)還能帶來(lái)一些新特性:

允許自定義JSX的標(biāo)簽名

生命周期鉤子(這一節(jié)暫不介紹這部分)

首先我們要定義一個(gè)Component的基礎(chǔ)類,在創(chuàng)建其它組件時(shí)都要繼承該類。我們需要一個(gè)帶有props入?yún)⒑?b>setState方法的構(gòu)造函數(shù),setState方法可以接收partialState作為入?yún)?lái)更新組件狀態(tài):

class Component{
    constructor(props){
        this.props = props;
        this.state = this.state || {}
    }
    
    setState(partialState){
        this.state = Object.assign({}, this.state, partialState);
    }
}

我們?cè)趧?chuàng)建組件時(shí)都會(huì)繼承上面這個(gè)類。組件的使用方法和原生的標(biāo)簽如div或者span一樣,直接像這樣就可以了。而且我們的createElement也不需要做修改,元素的type屬性可以直接取值為組件類,剩下的props屬性也不需要特別的處理。我們需要一個(gè)方法能根據(jù)傳入的元素來(lái)創(chuàng)建組件的實(shí)例(稱之為公共實(shí)例,其實(shí)就是根據(jù)這個(gè)構(gòu)造函數(shù)new出來(lái)的一個(gè)對(duì)象)。

function createPublicInstance(element, internalInstance){
    const {type, props} = element;
    const publicInstance = new type(props); // 這地方的type對(duì)應(yīng)組件的構(gòu)造函數(shù)
    publicInstance.__internalInstance = internalInstance;
    return publicInstance;
}

組件的內(nèi)部實(shí)例含有組件對(duì)應(yīng)的dom元素(內(nèi)部實(shí)例就是前幾節(jié)我們說(shuō)的實(shí)例,通過(guò)調(diào)用instantiate方法生成的)。公共實(shí)例與內(nèi)部實(shí)例的引用關(guān)系會(huì)被保存著,通過(guò)這個(gè)引用關(guān)系可以找到公共實(shí)例對(duì)應(yīng)的內(nèi)部實(shí)例及虛擬DOM,當(dāng)公共實(shí)例狀態(tài)發(fā)生變化時(shí),我們就可以只更新發(fā)生變化的內(nèi)部實(shí)例及其對(duì)應(yīng)的那部分虛擬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方法需要做一些改造。對(duì)組件來(lái)講,我們需要先創(chuàng)建公共實(shí)例(先new一個(gè)組建),然后調(diào)用組件的render方法來(lái)獲取組件內(nèi)部的元素,最后把獲取到的元素傳遞給instantiate方法。

function instantiate(element){
    const { type, props } = element;
    const isDomElement = typeof type === "string";
    
    if(isDomElement){ // 如果是原生的dom元素的話,直接創(chuàng)建實(shí)例
        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)建公共實(shí)例,然后再調(diào)用instantiate方法創(chuàng)建內(nèi)部實(shí)例
        const instance = {};
        // 這地方的element是一個(gè)type屬性為一個(gè)構(gòu)造函數(shù)的對(duì)象
        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;
    }
}

組件對(duì)應(yīng)的內(nèi)部實(shí)例和原生dom元素對(duì)應(yīng)的實(shí)例有些不一樣。組件內(nèi)部實(shí)例只會(huì)擁有一個(gè)子元素,即render方法返回的內(nèi)容,而原生dom元素則可以含有多個(gè)子元素。所以對(duì)于組件內(nèi)部實(shí)例來(lái)講,它們會(huì)有一個(gè)childInstance屬性而不是一個(gè)childInstances數(shù)組。此外,由于在進(jìn)行一致性校驗(yàn)時(shí)需要調(diào)用組件的render方法,所以組件內(nèi)部實(shí)例會(huì)保存對(duì)公共實(shí)例的引用(反過(guò)來(lái)公共實(shí)例也保存著對(duì)內(nèi)部實(shí)例的引用)。

接下來(lái)我們來(lái)處理下組件實(shí)例的一致性校驗(yàn)。因?yàn)榻M件的內(nèi)部實(shí)例只含有一個(gè)子元素(所有元素有一個(gè)統(tǒng)一的父類),只需要更新公共實(shí)例的props屬性,執(zhí)行render方法獲取子元素,然后再進(jìn)行一致性校驗(yàn)就可以了。

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;// 更新公共實(shí)例的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標(biāo)簽,并擁有了組件內(nèi)部狀態(tài),而且組件有變化時(shí)只會(huì)變更自己的那部分dom內(nèi)容。

相關(guān)內(nèi)容到此結(jié)束。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99870.html

相關(guān)文章

  • 構(gòu)建自己React:(4Components and State

    摘要:我們需要一個(gè)帶有入?yún)⒑头椒ǖ臉?gòu)造函數(shù),方法可以接收作為入?yún)?lái)更新組件狀態(tài)我們?cè)趧?chuàng)建組件時(shí)都會(huì)繼承上面這個(gè)類。我們需要一個(gè)方法能根據(jù)傳入的元素來(lái)創(chuàng)建組件的實(shí)例稱之為公共實(shí)例,其實(shí)就是根據(jù)這個(gè)構(gòu)造函數(shù)出來(lái)的一個(gè)對(duì)象。 翻譯自:https://engineering.hexacta.c... 上一節(jié)的代碼有一些問(wèn)題: 每次更新都會(huì)帶來(lái)整顆虛擬DOM樹(shù)的一致性校驗(yàn); 狀態(tài)是全局的(沒(méi)有私有狀...

    sixgo 評(píng)論0 收藏0
  • 程序員練級(jí)攻略(2018):前端性能優(yōu)化和框架

    摘要:,谷歌給的一份性能指南和最佳實(shí)踐。目前而言,前端社區(qū)有三大框架和。隨后重點(diǎn)講述了和兩大前端框架,給出了大量的文章教程和相關(guān)資源列表。我認(rèn)為,使用函數(shù)式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習(xí)慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個(gè)是我訂閱 陳皓老師在極客上的專欄《左耳聽(tīng)風(fēng)》...

    VEIGHTZ 評(píng)論0 收藏0
  • 程序員練級(jí)攻略(2018):前端性能優(yōu)化和框架

    摘要:,谷歌給的一份性能指南和最佳實(shí)踐。目前而言,前端社區(qū)有三大框架和。隨后重點(diǎn)講述了和兩大前端框架,給出了大量的文章教程和相關(guān)資源列表。我認(rèn)為,使用函數(shù)式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習(xí)慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個(gè)是我訂閱 陳皓老師在極客上的專欄《左耳聽(tīng)風(fēng)》...

    CoffeX 評(píng)論0 收藏0
  • 淺談MVC,MVP,MVVM漸進(jìn)變化及React與Vue比較

    摘要:將注意力集中保持在核心庫(kù),而將其他功能如路由和全局狀態(tài)管理交給相關(guān)的庫(kù)。此示例使用類似的語(yǔ)法,稱為。執(zhí)行更快,因?yàn)樗诰幾g為代碼后進(jìn)行了優(yōu)化?;诘哪0迨沟脤⒁延械膽?yīng)用逐步遷移到更為容易。 前言 因?yàn)闆](méi)有明確的界定,這里不討論正確與否,只表達(dá)個(gè)人對(duì)前端MV*架構(gòu)模式理解看法,再比較React和Vue兩種框架不同.寫(xiě)完之后我知道這文章好水,特別是框架對(duì)比部分都是別人說(shuō)爛的,而我也是打算把...

    DrizzleX 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

cncoder

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<