上一篇中,已经可以渲染原生的组件到页面,本节实现类式组件和函数式组件的渲染。首先使用官方的React框架,分别打印出类式组件和函数式组件的虚拟DOM。
class Demo1 extends React.Component{ //类式组件的Demo
render(){
return (
<div style={{color:"green"}} className="title" ref={c=>this.root =c} >
<h2>this is class component</h2>
</div>
)
}
}
function Demo2(){ //函数是组件的Demo
return (
<div style={{color:"red"}}>
<h2>this is function component</h2>
</div>
)
}
下面是类式组件的虚拟DOM, 可以看到type属性保存的就是Demo1这个类本身
继续把type属性展开,可以看到,render()函数的返回值,也就是返回的JSX的部分,被babel编译了,调用了createElement方法
因此对于类式组件,需要创建类的实例对象,然后调用render方法,该方法的返回值才是真正的虚拟DOM
同理,下面是函数式组件的虚拟DOM,可以看到type属性保存的就是Demo2这个类本身
查看type属性
对于函数式组件,该函数的返回值就是JSX表达式,才是真正的虚拟DOM
react-dom 文件中的写法
function render(VDOM, container){
let DOM = createDOM(VDOM)
container.appendChild(DOM)
}
function createDOM(VDOM){
if(Object(VDOM) !== VDOM){
return document.createTextNode(VDOM)
}
let {type, props} = VDOM
let DOM =null
if(typeof type === "function"){ //新增部分
if(type.isClassComponent){ //判断是类式组件还是函数式组件,分别处理
return handleClassComponent(VDOM)
}
return handleFunctionComponent(VDOM)
}else{
DOM = document.createElement(type)
}
updateProps(DOM, null, props)
let {children} = props
if(children){
handleChildren(DOM, children)
}
return DOM
}
function handleClassComponent(VDOM){ //对于类式组件
let {type, props} = VDOM
let classInstance = new type(props)
let realVDOM = classInstance.render() //render()的返回值才是JSX,也就是虚拟DOM
return createDOM(realVDOM)
}
function handleFunctionComponent(VDOM){
let {type, props} = VDOM
let realVDOM = type(props) //函数执行的返回值就是虚拟DOM
return createDOM(realVDOM)
}
function updateProps(DOM, oldProps, newProps){ //props:{chilren, className, style, onXXX}
if(newProps){
for(let key in newProps){
if(key === "children"){
continue
}else if(key === "style"){
let styleObject = newProps[key]
for(let item in styleObject){
DOM.style[item] = styleObject[item]
}
}else if(key.startsWith("on")){
DOM[key.toLocaleLowerCase()] = newProps[key]
}else{
DOM[key] = newProps[key]
}
}
}
if(oldProps){
for(let key in oldProps){
if(!newProps[key]) DOM[key] = null
}
}
}
function handleChildren(DOM, children){
if(children instanceof Array){
children.forEach(child => render(child, DOM) )
}else{
render(children, DOM)
}
}
const ReactDOM = {
render
}
export default ReactDOM
创建Component.js文件,用来编写Component这个父类
class Component {
static isClassComponent = true //静态属性,表示这个是类式组件
constructor(props){
this.props = props
}
}
export default Component
在react.js文件中,引入Component
import { REACT_ELEMENT } from "./constant"
import Component from "./component"
function createElement(type, config, children){ // 标签类别 config 标签内容
let key = null, ref = null
if(config){
key = config.key
ref = config.ref
delete config.key
delete config.ref
}
let props = {...config}
if(arguments.length >= 4){
props.children = Array.from(arguments).slice(2)
}else if(arguments.length == 3){
props.children = children
}
return {
$$typeof: REACT_ELEMENT,
type,
ref,
key,
props,
}
}
const React = {
createElement,
Component //class Xyyy extends React.Component
}
export default React
下图表示目前的文件结构
这样就可以渲染类式组件和函数式组件了