手寫render和ceateElement

jsx語法

首先介紹jsx語法 , 其實jsx= javascript + xml,看上去是html其實不是.javascript

let element = <h1 id='myid'>hello world</h1>

經過bable 轉義後變成html

let element= React.createElement('h1',{id:'myid'},'hello world')
 //這裏咱們稱React元素,這是React最小單位

render渲染

寫完React元素,就能夠render渲染,就能夠在頁面中呈現了.java

ReactDom.render(element,document.getELementById('root'))

那麼咱們按照源碼開始再手寫一下render和createElement

createElement

  1. createElement函數的目標是把傳進來的('h1',{id:'myid'},'hello world')參數變成一個React元素

如圖這個就是咱們要的react元素
圖片react

function createElement(type,config={},children){
      let props={};
      for(let propsName in config){
        props[propsName]=config[propsName]
      };
      let childrenLength = arguments.length-2;
      if(childrenLength==1){
        props.children=children
      }else if( childrenLength >1){
        props.children=Array.from(arguments).slice(2)
      }
      let element={type,props}
      return element
  }

思路:數組

  1. 三個參數,參數1是咱們的type可直接返回,參數2和參數3咱們須要把它們塞進一個props對象裏面
  2. 首先建立一個props空對象,遍歷config,依次添加進props對象裏
  3. 截取children長度,判斷長度如果1說明是文本節點可直接添加,大於1則是一個數組,咱們返回數組便可

render

render函數是把React元素(虛擬dom)渲染成htmlapp

function render(element,parentNode){
  if(typeof element == 'string' || typeof element =='number'){
    return parentNode.appendChild(document.createTextNode(element))
  }
  let {type,props}=element;
  let domElement = document.createElement(type);
  for(let propsName in props){
      switch(propsName){
        case propsName=='className':
          return domElement.className=props[propsName];
        case propsName=='style':
          let styobj=  props[propsName]
          for(let attr in styobj){
            domElement.style[attr]=styobj[attr]
          }
          return
         case  propsName=='children':
          let children = Array.isArray(props.children)?props.children:[props.children]
          children.forEach(element=>{
            render(element,domElement)
          })
          return
          default:
            domElement.setAttribute(propsName,props[propsName])
      }
  }
  parentNode.appendChild(domElement)
}

思路:dom

  1. render函數2個參數分別爲react元素,根組件,咱們先判斷react元素是否是string和number由於能夠直接渲染好比像這樣函數

    ReactDom.render('abc',document.getElementById('root'))
  2. 當參數1 是個react元素的時間,咱們就得去作判斷,首先咱們能夠分別解構出type,props,而後咱們用type建立出元素,遍歷props讓type元素依次添加屬性.
  3. 須要考慮特性狀況如className,style就得去分別去作處理在添加,其餘的直接用setAttribute添加進去.
  4. 最後經過根元素把咱們建立出來的appendChild添加進去.

當咱們元素是函數組件的時候

function Welcome(props){
    return React.createElement('h1',{id:'zhufeng'},props.name,props.age)
  }
  ReactDOM.render(element, document.getElementById('root'));

咱們得在render裏面去添加邏輯,只須要把這個函數執行後就可,由於它的返回值仍是咱們的react元素.this

function render(element,parentNode){
  if(typeof element == 'string' || typeof element =='number'){
    return parentNode.appendChild(document.createTextNode(element))
  }
     let {type,props}=element
    + if(typeof type == 'function'){
    + let newElemet=type(props)
    + type=newElemet.type;
    + props=newElemet.props;
  }
  //如下邏輯相同
}

當咱們元素是類組件的時候

class Welcome1 extends React.Components{
      render(){
        return React.createElement('h1',{id:'classwelcome'},this.props.name,this.props.age)
      }
  }

一樣的思路,咱們先去建立一個Components組件讓它去繼承.spa

class Components{
    static isReactComponents=true
    constructor(props){
      this.props=props
    }
  }

這個組件咱們只須要去傳遞props讓子組件去繼承就能夠,另外isReactComponents這個靜態屬性是用來標識是不是類組件.
接下來咱們繼續改render函數

function render(element,parentNode){
  if(typeof element == 'string' || typeof element =='number'){
    return parentNode.appendChild(document.createTextNode(element))
  }
     let {type,props}=element
     + if(type.isReactComponents){
     +    let newElemet=new type(props).render()
     +     type=newElemet.type;
     +     props=newElemet.props;
     + }else if(typeof type == 'function'){
     +    let newElemet=type(props)
     +     type=newElemet.type;
     +     props=newElemet.props;
     + }
  }
  //如下邏輯相同
}

那麼咱們就能夠順利跑通啦.

相關文章
相關標籤/搜索