ReactDOM.render的渲染原理(理解)

1,247 阅读1分钟

ReactDOM.render的渲染原理

在react项目中,之所以可以在函数/组件中直接写模板结构,是因为最后babel都会帮我们把这些模板转译成 React.createElemen(config) 的形式,这也就是为什么我们在每一个组件中明明没有主动调用React,但是却要引入react的原因。

// 举例
import React from 'react';
import ReactDOM from 'react-dom';

let h = React.createElement(
  'div',{className:'box',style:{fontSize:'30px', color:'green'}},'第一个儿子',
  React.createElement('h2',{style:{color:'red',textAlign: 'center'}},'第二个儿子')
  );

let p = <div className='box' style={{fontSize:'30px', color:'green'}}>
  第一个儿子
  <h2 style={{color:'red',textAlign: 'center'}}>第二个儿子</h2>
</div>
ReactDOM.render(<>
   {h}
   {p}
  </>,
document.getElementById('root'));
// p和h渲染的页面是一样的

渲染结果:

渲染结果

下面简单实现 React.createElement 和 ReactDOM.render 的功能
let React = {
  createElement(type, attrs,...children){
    // 第一步:创建真实的DOM
    let el = document.createElement(type); 
    // 第二步:对行内属性进行处理
    let keys = Object.keys(attrs);
    for(let i=0; i<keys.length; i++) {
      let key = keys[i];
      switch(key) {
        case 'className':
          el.setAttribute('class', attrs[key]);
          break;
        case 'htmlFor':
          el.setAttribute('for', attrs[key]);
          break;
        case 'style':
          let str = ''
          Object.keys(attrs.style).forEach(item=>{
            str += `${React.changeStr(item)}:${attrs.style[item]};`
          });
          el.setAttribute('style', str);
          break;
        default:
          el.setAttribute(key, attrs[key]);
      }
    }
    // 第三步:处理后代元素
    children.forEach(child=>{
      if(typeof child === 'string') {
        el.appendChild(document.createTextNode(child))
      }else {
        // console.log(child, 'else')
        el.appendChild(child)
      }
    })
    // 最后,返回创建的真实DOM
    return el;
  },
  changeStr(str){
    // 辅助函数:目的是将驼峰命名的属性转为串式命名
    // 例如:fontSize -> font-size
    return str.replace(/[A-Z]/g, b=>{
      return '-' + b.toLowerCase();
    }).replace(/^-/, '')
  }
};

let ReactDOM = {
  render(el, container){
    // el 是React.createElement 处理之后的拿到的真实DOM,直接操作即可
    // 将转化后拿到的真实DOM插入到container中
    container.appendChild(el);
  }
}

let h = React.createElement(
  'div',{className:'box',style:{fontSize:'30px', color:'green'}},'第一个儿子',
  React.createElement('h2',{style:{color:'red',textAlign: 'center'}},'第二个儿子')
  );

ReactDOM.render(h, document.getElementById('root'));