在上一篇文章的基础上添加处理函数组件渲染。
1、改造index.js为函数组件
// indeximport React from './react';import ReactDOM from './react-dom';function FunctionComponent(props) {return (<div className="title" style={{ background: 'red' }}><span>{props.name}</span></div>)}ReactDOM.render(<FunctionComponent name="xiaoming" />,document.getElementById('root'));
2、添加处理函数组件
createDom函数增加处理函数组件逻辑:
mountFunctionComponent函数实现:实现逻辑其实很简单,就是调用函数组件,传入props,使其成为原生组件,重复调用原生组件逻辑。createElement
3、实现效果

4、完整代码
// react-dom.js/*** createElement编译出来的结果* {"type":"div","key":null,"ref":null,* "props":{"className":"title","style":{"color":"red"},* "children":{"type":"span","key":null,* "ref":null,"props":{"children":"hello word"}*//*** 1.把虚拟DOM变为真实DOM;* 2.把虚拟DOM属性同步到真实DOM上;* 3.把虚拟DOM上的children也变成真实DOM挂载到自己的DOM上;* 4.把最终DOM挂载到容器上;* @param {*} vdom 要渲染的虚拟DOM* @param {*} container 虚拟DOM转换成真实DOM,并插入到容器中*/function render(vdom, container) {const dom = createDom(vdom)container.appendChild(dom)}/*** 虚拟dom变为真实dom* @param {*} vdom 虚拟dom*/function createDom(vdom) {// 如果是字符串或者数字,直接返回真实节点if (['number', 'string'].includes(typeof vdom)) {return document.createTextNode(vdom)}// 否则它就是一个react元素了const { type, props } = vdomlet domif (typeof type === 'function') {// 函数组件直接返回return dom = mountFunctionComponent(vdom)} else {// 原生组件dom = document.createElement(type)}// 将虚拟dom属性更新到真实dom上updateProps(dom, props)// 如果儿子只有一个儿子,并且儿子是文本节点if (['number', 'string'].includes(typeof props.children)) {dom.textContent = props.children// 如果儿子是一个对象,并且是一个虚拟dom,递归调用render} else if (typeof props.children === 'object' && props.children.type) {// 把儿子变成真实dom,插入到自己身上render(props.children, dom)// 如果儿子是一个数组,说明儿子不止一个} else if (Array.isArray) {reconcileChildren(props.children, dom)} else {document.textContent = props.children ? props.children.toString() : ""}// // 把真实dom作为一个虚拟属性放在虚拟dom上,为以后更新做准备// vdom.dom = domreturn dom}/*** @param {*} childrenVdom 儿子们的虚拟dom* @param {*} parentDom 父的真实dom*/function reconcileChildren(childrenVdom, parentDom) {for (const childVdom of childrenVdom) {render(childVdom, parentDom)}}/*** 把一个类型为自定义函数组件的虚拟dom转换为真实dom并返回* @param {*} vdom 自定义函数虚拟dom*/function mountFunctionComponent(vdom) {const { type:FunctionComponent, props } = vdom// 直接调用let renderVdom = FunctionComponent(props)return createDom(renderVdom)}/*** 将虚拟dom属性更新到真实dom上* @param {*} dom 真实dom* @param {*} newProps 新属性*/function updateProps(dom, newProps) {for (const key in newProps) {if (key === 'children') continue// style单独处理,因为dom不支持if (key === 'style') {const styleObj = newProps.stylefor (let attr in styleObj) {dom.style[attr] = styleObj[attr]}} else {dom[key] = newProps[key]}}}const ReactDom = { render }export default ReactDom
5、源代码
本文代码:https://gitee.com/linhexs/react-write/tree/2.react-FunctionComponent-render/
