手写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;
     + }
  }
  //如下逻辑相同
}

那么咱们就能够顺利跑通啦.

相关文章
相关标签/搜索