Skip to content

实现类组件 ​

本节目标:理解“实现类组件”的核心思路,并能把它用于实际开发或面试表达。 类组件实现和函数组件类似; 我们会在createDOM时新加一个判断; 然后调用mountClassComponent==方法;==

src\index.js
import React from "./react";
import ReactDOM from "./react-dom";
class ClassComponent extends React.Component {
  render() {
    return (
      <div
        className="title"
        style={{ color: 'red' }}
      >
        <span>{this.props.name}</span>
        {this.props.children}
      </div>
    );
  }
}
let element = <ClassComponent name="hello">world</ClassComponent>;
ReactDOM.render(element, document.getElementById("root"));

新建

src\component.js
export class Component {
  static isReactComponent = true
  constructor(props) {
    this.props = props;
  }
}
src\react.js
import { wrapToVdom } from "./utils";
import { wrapToVdom } from "./utils";
import { Component } from './

==c==

omponent';
function createElement(type, config, children) {
  let ref;
  let key;
  if (config) {
    delete config.__source;
    delete config.__self;
    ref = config.ref;
    delete config.ref;
    key = config.key;
    delete config.key;
  }
  let props = { ...config };
  if (arguments.length > 3) {
    props.children = Array.prototype
      .slice.call(arguments, 2)
      .map(wrapToVdom);
  } else {
    props.children = wrapToVdom(children);
  }
  return {
    type,
    ref,
    key,
    props,
  };
}
const React = {
  createElement,
  Component
};
export default React;
src\react-dom.js
import { REACT_TEXT } from "./constants";
function render(vdom, container) {
  mount(vdom, container);
}
export function mount(vdom, container) {
  let newDOM = createDOM(vdom);
  container.appendChild(newDOM);
}

新加的判断

export function createDOM(vdom) {
  let { type, props } = vdom;
  let dom;
  if (type === REACT_TEXT) {
    dom = document.createTextNode(props.content);
  } else if (typeof type === "function") {
    if (type.isReactComponent) {
      return mountClassComponent(vdom);
    } else {
      return mountFunctionComponent(vdom);
    }
  } else {
    dom = document.createElement(type);
  }
  if (props) {
    updateProps(dom, {}, props);
    if (typeof props.children == "object" && props.children.type) {
      mount(props.children, dom);
    } else if (Array.isArray(props.children)) {
      reconcileChildren(props.children, dom);
    }
  }
  vdom.dom = dom;
  return dom;
}

主要做以下几件事件:

  • 创建类实例
  • 调用类实例的render方法来生成renderVdom;
  • 同样,将生成的renderVdom以oldRenderVdom的属性名挂靠到类组件本身的vdom上去;
  • 使用生成的renderVdom创建真实dom,并返回;
function mountClassComponent(vdom) {
  let { type, props } = vdom;
  let classInstance = new type(props);
  let renderVdom = classInstance.render();
  vdom.oldRenderVdom = renderVdom;
  return createDOM(renderVdom);
}
function mountFunctionComponent(vdom) {
  let { type, props } = vdom;
  let renderVdom = type(props);
  vdom.oldRenderVdom = renderVdom;
  return createDOM(renderVdom);
}
function updateProps(dom, oldProps, newProps) {
  for (let key in newProps) {
    if (key === "children") {
      continue;
    }
    if (key === "style") {
      let style = newProps[key];
      for (let attr in style) {
        dom.style[attr] = style[attr];
      }
    } else {
      dom[key] = newProps[key];
    }
  }
}
function reconcileChildren(childrenVdom, parentDOM) {
  for (let i = 0; i < childrenVdom.length; i) {
    let childVdom = childrenVdom[i];
    mount(childVdom, parentDOM);
  }
}
const ReactDOM = {
  render,
};
export default ReactDOM;

本站总访问 — 次