React源码:React.Component与React.createElement实现

490 阅读1分钟

继承React.component

自定义的组件要继承React.compoent,自定义的类中必须要实现一个render方法。

class Clock extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props}.</h2>
      </div>
    );
  }
}

通过super(props)将自定义组件的props绑定到了实例对象上,不需要重复书写this.props = props,在render函数中可以直接使用this.props。因为react.component内部的实现如下

function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  // If a component has string refs, we will assign a different object later.
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

render函数中的JSX-react.createElement

render函数中的JSX(HTML)代码会被@babel/plugin-transform-react-jsx这个babel转译插件转换为React.creactElement

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
      </div>
    );
  }
}

等效于

class Clock extends React.Component {
  render() {
    return (
      React.createElement(
        'div',
        {
          title: 'aa',
        },
        React.createElement('h1', {}, 'Hello, world!')
      )
    );
  }
}

所以出现了JSX语法的模块一定要引入react。

react.createElement的作用是返回一个虚拟dom,大致的代码如下。

function createElement(type, attributes, ...children) {
  let e
  if (typeof type == 'string') {
    e = new ElementWrapper(type)
  } else {
    e = new type()
  }
  for (let p in attributes) {
    e.setAttribute(p, attributes[p])
  }
  let insertChildren = (children) => {
    for (let child of children) {
      if (typeof child === 'string') {
        child = new TextWrapper(child)
      }
      if (typeof child === 'object' && child instanceof Array) {
        insertChildren(child)
      } else {
        e.appendChild(child)
      }
    }
  }
  insertChildren(children)
  return e
}

e就是一个虚拟dom。

  • 如果是一个原生的dom节点会调用new ElementWrapper(type)
  • 如果是自定义的组件会调用new type(),最后还是转化为new ElementWrapper(type) ElementWrapper的实现如下
class ElementWrapper {
  constructor(type) {
    this.root = document.createElement(type)
  }
  setAttribute(name, value) {
    this.root.setAttribute(name, value)
  }
  appendChild(component) {
    this.root.appendChild(component.root)
  }
}