react

react源码分析(2):实现一个vdom结构

2019-03-30  本文已影响0人  月肃生

前言

    可以试着仿照上一节react的用法写一个属于自己的react

  1. react.js

简单实现react的createElement和Component类,createElement参数(type, props,...children)基本参照原版实现

// react Component类
class Component {
  constructor(props) {
    this.props = props
  }
  render() {
    
  }
}
// 生成一个react组件(实质上是一个对象)
function createElement(type, props, ...children){
  // 参数分别是 type: 标签名或者Component对象
  // props 是vdom的一些属性,像点击事件或者参数
  // children 是多个参数,也是一个vdom,可以是字符串
  let vdom = {
    key: props && props.key,
    type, // 组件类型,可以是html标签或者自己编写的react组件
    props: {
      ...props,
      ref: null, // 一个方法
    }
  }
  // 将children也作为props的一部分
  if(children.length === 1) {
    vdom.props.children = children[0]
  }else if(children.length > 1) {
    vdom.props.children = children
  }
  return vdom
}

window.React = {
  createElement: createElement,
  Component: Component
}
  1. react-dom.js

针对vdom对象生成真实的dom节点

// 参数 vdom: vdom对象,node: 挂载的节点
function render(vdom, node) {
  node.appendChild(renderNode(vdom))
}
// 如何根据vdom生成真实节点
function renderNode(vdom) {
  const {type, props} = vdom
  const children = props.children
  let node
  // 判断节点是不是普通html标签,没有做细致判断
  if(typeof(type) === 'string') {
    node = document.createElement(type) // 创建dom节点
  // props暂时不处理
    // 字节点处理
    if(children) {
      const classType = typeof(children)
      if(classType === 'string') { // 判断children是不是只是一个文本,文本可以直接设置文本
        node.innerText = children
      }else if(children instanceof Array) { // 如果是数组,就循环递归renderNode
        children.map(child => {
          node.appendChild(renderNode(child)) 
        })
      }else if(children.type.prototype.__proto__ === React.Component.prototype){ // 如果是react组件就需要根据prop 初始化new 对象了
        node.appendChild(renderNode(new children.type().render())) // 新建react组件需要调用render获取vdom
      }
    }
  } else if(type.prototype.__proto__ === React.Component.prototype){ // 判断是不是react组件,初始化new 对象了
    const Element = new type(props)
    node = renderNode(Element.render())
  }
  return node
} 

window.ReactDOM = {
  render: render
}
  1. index.js

ReactDOM.render和createElement都实现,咱们可以实际使用了试试

class List extends React.Component {
  render() {
    return React.createElement(
      "ul",
      null,
      React.createElement("li", null, "1"),
      React.createElement("li", null, "2"),
      React.createElement("li", null, "3"),
      React.createElement("li", null, "4"),
    );
  }
}

ReactDOM.render(
  React.createElement(List, null),
  document.getElementById("app")
);

总结

虚拟dom的实现还是很简单的,下一节将会针对react的另一个点tree diff算法
github地址

上一篇 下一篇

猜你喜欢

热点阅读