手写react渲染代码【只是实现了元素渲染(没有实现事件、生命周期、hooks等)】

119 阅读1分钟
  • 主要实现createElement方法 和 render方法
  • createElement方法实现了对 组建props属性的创建和子节点属性children的创建
function createElement(type, config = {}, ...childrens) {
  let props = {}
  for (const key in config) {
    props[key] = config[key]
  }
  props.children = childrens
  return { type, props }
}
  • render方法实现了对原生节点、函数节点、类节点的创建方式,函数组建和类组建最总都会得到原生节点。
  • 得到原生节点递归判断是否含有子节点,有的话继续使用render方法,直到文本节点为止。
// 声明一个ReactComponent 组建 供继承
class Component {
    constructor(props) {
        props = this.props
    }
    static isReactComponent = true
}

function render(node, parent) {
  if (typeof node === 'string') {
    return parent.appendChild(document.createTextNode(node))
  }

  let { type, props } = node

  // class组建
  if(type.isReactComponent) {
    let classEle = new type(props).render()
    type = classEle.type
    props = classEle.props
  }

  // 函数组建
   else if  (typeof type === 'function') {
    let funEle = type(props)
    type = funEle.type
    props = funEle.props
  }


  // 原生组建
  let ele = document.createElement(type)
  for (const key in props) {
    switch (key) {
      case 'children':
        break
      case 'className':
        ele.className = props.className
        break;
      case 'style':
        let styleObj = props.style
        for (let attr in styleObj) {
          ele.style[attr] = styleObj[attr]
        }
        break;
      default:
        ele.setAttribute(key, props[key])
    }
  }

  //处理儿子节点
  if (Array.isArray(props.children)) {
    props.children.forEach(element => {
      render(element, ele)
    });
  }

  parent.appendChild(ele)
}

  • 举例:
function Hello() {
  let msg = 'function component'
  return createElement('h2', {style: { color: 'red' }}, msg)
}

class World extends Component{
    constructor(props){
        super(props)
    }
    render() {
        return createElement('h2', {}, createElement('span', {}, 'class'))
    }
}


let ele = createElement('h1', { className: 'hello' }, createElement('span', {style: { color: 'red' }}, 'hello'), createElement('span', {style: { 'fontSize': '18px' }}, ' world'), createElement(Hello, {}),createElement(World, {}))


render(ele, document.querySelector('#root'))

借鉴:www.cnblogs.com/lyt0207/p/1…