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

資訊專欄INFORMATION COLUMN

從頭實(shí)現(xiàn)一個(gè)簡(jiǎn)易版React(二)

vvpvvp / 1839人閱讀

摘要:寫在開頭從頭實(shí)現(xiàn)一個(gè)簡(jiǎn)易版一地址上一節(jié),我們?cè)敿?xì)介紹了實(shí)現(xiàn)一個(gè)簡(jiǎn)易的思路以及整體的結(jié)構(gòu),但是對(duì)于渲染和更新的原理,卻還沒有提及,因此,本節(jié)我們將重點(diǎn)放在的渲染上。

寫在開頭

從頭實(shí)現(xiàn)一個(gè)簡(jiǎn)易版React(一)地址:https://segmentfault.com/a/11...
上一節(jié),我們?cè)敿?xì)介紹了實(shí)現(xiàn)一個(gè)簡(jiǎn)易R(shí)eact的思路以及整體的結(jié)構(gòu),但是對(duì)于渲染和更新的原理,卻還沒有提及,因此,本節(jié)我們將重點(diǎn)放在vDom的渲染上。

進(jìn)入正題

我們把React元素分為text,basic,custom三種,并分別封裝了三種vDom的ReactComponent,用來(lái)處理各自的渲染和更新,在這里,我們將重心放在各自ReactComponet的mount方法上。

ReactTextComponent

ReactTextComponent用來(lái)處理文本節(jié)點(diǎn),為了標(biāo)識(shí)方便,在返回的內(nèi)容上加了span標(biāo)簽。

// 用來(lái)表示文本節(jié)點(diǎn)在渲染,更新,刪除時(shí)應(yīng)該做的事情
class ReactTextComponent extends ReactComponent {
  // 渲染
  mountComponent(rootId) {
    this._rootNodeId = rootId
    return `${this._vDom}`
  }
}
//代碼地址:src/react/component/ReactTextComponent.js

ReactTextComponent的mount方法非常簡(jiǎn)單,打上標(biāo)識(shí)符,將內(nèi)容插入標(biāo)簽內(nèi),并把標(biāo)簽內(nèi)容返回就可以了。

ReactDomComponent

這個(gè)類用來(lái)處理原生節(jié)點(diǎn)的vDom,在將vDom渲染為原生DOM時(shí),要考慮3點(diǎn):

元素類型

拼湊屬性,包含普通屬性及事件的處理

子節(jié)點(diǎn)的遞歸渲染

代碼如下:

// 用來(lái)表示原生節(jié)點(diǎn)在渲染,更新,刪除時(shí)應(yīng)該做的事情
class ReactDomComponent extends ReactComponent {
  constructor(vDom) {
    super(vDom)
    this._renderedChildComponents = null
  }

  // 渲染
  mountComponent(rootId) {
    this._rootNodeId = rootId

    const { props, type, props: { children = [] } } = this._vDom,
      childComponents = []

    // 設(shè)置tag,加上標(biāo)識(shí)
    let tagOpen = `${type} data-reactid=${this._rootNodeId}`,
      tagClose = `/${type}`,
      content = ""

    // 拼湊屬性
    for (let propKey in props) {
      // 事件
      if (/^on[A-Za-z]/.test(propKey)) {
        const eventType = propKey.replace("on", "")
        $(document).delegate(`[data-reactid="${this._rootNodeId}"]`, `${eventType}.${this._rootNodeId}`, props[propKey])
      }

      // 普通屬性,排除children與事件
      if (props[propKey] && propKey !== "children" && !/^on[A-Za-z]/.test(propKey)) {
        tagOpen += ` ${propKey}=${props[propKey]}`
      }
    }

    // 獲取子節(jié)點(diǎn)渲染出的內(nèi)容
    children.forEach((item, index) => {
      // 再次使用工廠方法實(shí)例化子節(jié)點(diǎn)的component,拼接好返回
      const childComponent = instantiateReactComponent(item)
      childComponent._mountIndex = index

      childComponents.push(childComponent)

      // 子節(jié)點(diǎn)的rootId是父節(jié)點(diǎn)的rootId加上索引拼接的值
      const curRootId = `${this._rootNodeId}.${index}`
      // 得到子節(jié)點(diǎn)的渲染內(nèi)容
      const childMarkup = childComponent.mountComponent(curRootId)
      // 拼接
      content += childMarkup

      // 保存所有子節(jié)點(diǎn)的component
      this._renderedChildComponents = childComponents
    })

    return `<${tagOpen}>${content}<${tagClose}>`
  }
}
//代碼地址:src/react/component/ReactDomComponent.js

在React的官方實(shí)現(xiàn)中,自己實(shí)現(xiàn)了一套事件系統(tǒng),這里用了jQuery的事件代替。
在樣式上,需要基于傳入的style對(duì)象創(chuàng)建樣式,這里也暫時(shí)忽略了。

ReactCompositComponent

在創(chuàng)建自定義組件時(shí),通常會(huì)這樣創(chuàng)建

import React from "react"

class App extends React.Component {
  render() {
    return (
       
    )
  }
}

所以,第一步,我們先實(shí)現(xiàn)Component這個(gè)父類

// 所有自定義組件的父類
class Component {
  constructor(props) {
    this.props = props
  }

  setState(newState) {
    this._reactInternalInstance.updateComponent(null, newState)
  }
}
//代碼地址:src/react/Component.js

Component類上我們主要實(shí)現(xiàn)了setState方法,至于有什么用,我們放在更新里說(shuō)。
在自定義組件的vDom中,type保存的是我們創(chuàng)建的Component的引用,所以在ReactCompositeComponent的mount方法中。我們首先根據(jù)vDom的type創(chuàng)建組件的實(shí)例,在以此調(diào)用它初始渲染的生命周期方法,render方法。
在render方法中,返回了組件渲染內(nèi)容的vDom,我們根據(jù)這個(gè)vDom創(chuàng)建它的ReactComponent并調(diào)用mount(),就得到了真實(shí)的渲染內(nèi)容。
貼代碼:

export default class extends ReactComponent {
  constructor(element) {
    super(element)
    // 存放對(duì)應(yīng)的組件實(shí)例
    this._instance = null
    this._renderedComponent = null
  }

  // 渲染
  mountComponent(rootId) {
    this._rootNodeId = rootId
    const { type: Component, props } = this._vDom

    // 獲取自定義組件的實(shí)例
    const inst = new Component(props)
    this._instance = inst

    // 保留對(duì)當(dāng)前component的引用,下面更新時(shí)會(huì)用到
    inst._reactInternalInstance = this

    inst.componentWillMount && inst.componentWillMount()

    // 調(diào)用自定義組件的render方法,返回一個(gè)Vdom
    const renderedVdom = inst.render()

    // 獲取renderedComponent的component
    const renderedComponent = instantiateReactComponent(renderedVdom)
    this._renderedComponent = renderedComponent

    // 得到渲染之后的內(nèi)容
    const renderMarkup = renderedComponent.mountComponent(this._rootNodeId)

    // 在React.render方法最后觸發(fā)了mountReady事件,所在在這里監(jiān)聽,在渲染完成后觸發(fā)
    $(document).on("mountReady", () => {
      inst.componentDidMount && inst.componentDidMount()
    })

    return renderMarkup
  }
}
// 代碼地址:src/react/component/ReactCompositeComponent.js

從這里可以看出,自定義組件的mount方法并不負(fù)責(zé)具體的渲染,這些都交給了它的render,它把重心放在了創(chuàng)建對(duì)象和調(diào)用生命周期上。

總結(jié)

文章到這,我們的簡(jiǎn)易版react已經(jīng)初步實(shí)現(xiàn)了虛擬DOM的創(chuàng)建,生命周期的調(diào)用,虛擬DOM的遞歸渲染和事件處理。
總結(jié)一下,每一個(gè)vDom都有ReactComponent相對(duì)應(yīng),遞歸渲染的本質(zhì)無(wú)非就是獲取每個(gè)vDom的ReactComponent,并調(diào)用它的mount方法。
以上就是整個(gè)渲染的思路,下節(jié)我們將實(shí)現(xiàn)它的diff算法以及更新。
下一節(jié)地址:https://segmentfault.com/a/11...

參考資料,感謝幾位前輩的分享:
https://www.cnblogs.com/sven3...
https://github.com/purplebamb...
陳屹 《深入React技術(shù)?!?/p>

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

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

相關(guān)文章

  • 從頭實(shí)現(xiàn)一個(gè)簡(jiǎn)易React(三)

    摘要:寫在開頭從頭實(shí)現(xiàn)一個(gè)簡(jiǎn)易版二地址在上一節(jié),我們的已經(jīng)具備了渲染功能。參考資料,感謝幾位前輩的分享陳屹深入技術(shù)棧 寫在開頭 從頭實(shí)現(xiàn)一個(gè)簡(jiǎn)易版React(二)地址:https://segmentfault.com/a/11...在上一節(jié),我們的react已經(jīng)具備了渲染功能。在這一節(jié)我們將著重實(shí)現(xiàn)它的更新,說(shuō)到更新,大家可能都會(huì)想到React的diff算法,它可以說(shuō)是React性能高效的保...

    yvonne 評(píng)論0 收藏0
  • 從頭實(shí)現(xiàn)一個(gè)簡(jiǎn)易React(一)

    摘要:既然看不懂,那就看看社區(qū)前輩們寫的一些源碼分析文章以及實(shí)現(xiàn)思路吧,又這么過(guò)了幾天,總算是摸清點(diǎn)思路,于是在參考了前輩們的基礎(chǔ)上,實(shí)現(xiàn)了一個(gè)簡(jiǎn)易版的??偨Y(jié)以上就是實(shí)現(xiàn)一個(gè)的總體思路,下節(jié)我們重點(diǎn)放在不同的上。 寫在開頭 工作中使用react也很長(zhǎng)一段時(shí)間了,雖然對(duì)它的用法,原理有了一定的了解,但是總感覺停留在表面。本著知其然知其所以然的態(tài)度,我試著去看了react源碼,幾天下來(lái),發(fā)現(xiàn)并不...

    meislzhua 評(píng)論0 收藏0
  • 基于react native的登錄界面demo 超簡(jiǎn)易教程 redux

    摘要:登錄視圖登陸失敗用戶名或密碼不能為空彈出提示框成功是點(diǎn)擊登錄按鈕后調(diào)用的函數(shù),這里的功能比較簡(jiǎn)單。通過(guò)把發(fā)出去密碼登錄聲明組件需要整個(gè)中的哪一部分?jǐn)?shù)據(jù)作為自己的將和組件聯(lián)系在一起編寫是負(fù)責(zé)生成的,所以在大項(xiàng)目中還會(huì)用到合并。 本豬說(shuō) 本豬豬剛學(xué)react,也剛看RN,就叫寫這個(gè),苦不堪言,搭環(huán)境就搭了好久。看網(wǎng)上教程也是改了好多小地方才寫完了。本著雷鋒精神手把手教你寫(假的)。 sho...

    scq000 評(píng)論0 收藏0
  • 關(guān)于Vue2一些值得推薦的文章 -- 五、六月份

    摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...

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

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

0條評(píng)論

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