美文网首页
react jsx渲染原理分析

react jsx渲染原理分析

作者: Mr无愧于心 | 来源:发表于2019-03-10 22:00 被阅读0次

    jsx的使用

    let data=123;
    ReactDOM.render(<div>
                <h2>hello</h2>
                <p>{data}</p>
                <Child/>
            </div>,
            document.querySelector("#root")
    
    • 注意事项
      1. {}
        中括号中可以放js表达式
        不能放对象(会报错),数组中的项也不能是对象
        可以放函数,但函数执行需要有返回值(否则报错)
      
      1. 循环绑定
      let arr=['a','b','c','d']
      ReactDOM.render(<ul>
      {
        arr.map((item,index)=>{//如果{}中是个函数的话 函数执行必须要有返回值,否则会报错。
          return <li key={index}>{item}</li>
        })
      }
      </ul>,root)
      
      let arr=[<div>hello</div>,<div>world</div>,<p>haha</p>]
      ReactDOM.render(<ul>
      {=arr}
      </ul>,root)
      
      1. 判断(需要使用三元运算符)
       let data={show:true};
       ReactDOM.render(<div>{data.show?123:''}</div>,root)
      
      1. className代替class
      ReactDOM.render(<div className={class1}>123</div>,root)
      
      1. style
      ReactDOM.render(<div style={{color:red}}>123</div>,root)
      
      or
      let style1={color:red}
      ReactDOM.render(<div style={style1}>123</div>,root)
      
      5.只能有一个顶级元素
      jsx语法中只能有一个顶级标签(元素)这和react的diff算法相关
      
      1. false,null,undefined,和 true 都是有效的的 children(子元素) 。但是并不会被渲染,下面的JSX表达式渲染效果是相同的,都是空
      <div />
        <div></div>
        <div>{false}</div>
        <div>{null}</div>
        <div>{undefined}</div>
        <div>{true}</div>
      </div>
      
      1. label的for属性用htmlFor代替
      ReactDOM.render(<label htmlFor="name" ></label>,root)
      

    jsx的编译过程

    1. 有 JSX 的地方,在文件开头就需要引入 React,因为实际上 JSX 是使用了 React.createElement,JSX 只是一个JS 的语法糖,所以需要引入 React 包,否则会报错。
    2. react-dom 是一个把React 代码渲染到网页端的包,主要利用了render函数。
    • 示例:babel编译jsx
    ReactDom.render(<ul className="list">
       <li className="item">a</li>
       <li className="item">b</li>
     </ul>,root)
    //转化为
    createElement('ul',{className:'item'},[
        createElement('li',{class:'item'},['a']),
        createElement('li',{class:'item'},['b']),
    ])
    
    • createElement函数的实现
      createElement执行会把jsx转化成为一个虚拟DOM,就是一个对象
    vertualDom <==>
    {
      type:'ul',
      props:{class:'list',children:[
          {
              type:'li',
              props:{class:'item',children:'a'},
               key:null,
               ref:null
          },
          {
              type:'li',
              props:{class:'item',children:'b'},
               key:null,
               ref:null
          },
      ]},
      key:null,
      ref:null
    }
    

    实现

    //函数接受三个参数type,props,children,产出一个虚拟DOM对象
    //如果props中有ref或key,就把ref或key放到外边,props中的ref或key为undefined,否则外边的ref或key为null;
    //如果有childs,就把childs放到props的children上,如果childs只有一个,就是一个字符串,否租就是一个数组
    function createElement(type,props,...childs){
        props=props||{}
        let ref=null,key=null;
        if(ref in props){
            ref=props.ref;
            props.ref=undefined;
        }else{
            ref=null;
        }
        if(key in props){
            key =props.key ;
            props.key =undefined;
        }else{
            key =null;
        }
        let obj={
          type,
          props:{
            ...props,
            //如果没有childs就是"",如果有一项就是一个字符串,如果有多项就是一个数组
            children:childs.length<=1?(childs[0]||''):childs
          },
          key,
          ref,
        }
      return obj;
    }
    
    • render函数的实现
      render将createElement中传出的虚拟DOM转化为真实的DOM,挂载到页面上
    //函数传入虚拟DOM,容器和执行结束后的回调函数
    function render(objJSX,container,callback){
        let {type,props}=objJSX;
        let  newElement=document.createElement(type);
        for(let attr in props){
          let value=props[attr];
          if(props.hasOwnProperty(attr))break;
          if(typeof value=='undefined')break;
          if(attr.startsWith('on')){//事件处理
            let attch=attr.slice(2).toLowerCase();
            newElement.addEventListener(attch,value,false);
            continue;
          }
          switch(attr.toUpperCase){
            case 'CLASSNAME'://class特殊处理
              newElement.className=value;
              break;
            case 'STYLE'://style特殊处理
              for(let st in attr){
                newElement.style[st]=attr[st]
              }
              break;
            case 'CHILDREN'://children特殊处理
              !value intenceof Array?value =[value ]:null;//不是数组变成数组
              value.forEach((item)=>{
                if(typeof item=='string'){//是个字符串,直接插入
                   newElement.appendChild(document.createTextNode(item))
                }else{//是一个对象,递归调用
                  render(item,newElement)
                }
              })
              break;
            default://普通属性
            newElement.setAttribute(attr,value);
          }
        }
        container.appendChild(newElement);
        callback&&callback();
    }
    
    

    相关文章

      网友评论

          本文标题:react jsx渲染原理分析

          本文链接:https://www.haomeiwen.com/subject/jvxzkqtx.html