Appearance
实现类组件
本节目标:理解“实现类组件”的核心思路,并能把它用于实际开发或面试表达。 类组件实现和函数组件类似; 我们会在
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;