初始化渲染的过程,咱们能够间接对应到React程序中ReactDOM.render函数调用后的后果。

1.环境筹备

初始化我的项目:npx create-react-app simple-react
删除一些代码,最要害的内容就是:
src/index.js
public/index.html
package.json中的dependencies和scripts:

2.JSX介绍

JSX是JavaScript的一种语法扩大。
JSX到一般Javascript的代码的转化是通过babel实现的。

3.React.createElement编写

DISABLE_NEW_JSX_TRANSFORM=true 禁用掉新的jsxdev转换,应用React.createElement

这个迷你的包(cross-env)可能提供一个设置环境变量的scripts,让你可能以unix形式设置环境变量,而后在windows上也能兼容运行。
npm i cross-env -D
package.json
"start": "cross-env DISABLE_NEW_JSX_TRANSFORM=true react-scripts start",

react17之前通过Babel把jsx转换为虚构DOM
<div> Hello Simple React </div>
React.createElement("div", null, "Hello Simple React")

react.js

import { REACT_ELEMENT } from "./utils"function createElement(type, properties, children) {    // debugger    let ref = properties.ref || null    let key = properties.key || null        // 属性能够是可读的、可写的或可删除的。        // 属性能够是可枚举的(能够通过for…in循环枚举)或不可枚举的。        // 能够通过Object.defineProperty()等办法定义属性的个性。        ;['key', 'ref', '__self', '__source'].forEach(key => {            delete properties[key]        })    let props = { ...properties }    //传参大于3    if (arguments.length > 3) {        console.log(arguments)        props.children = Array.prototype.slice.call(arguments, 2)    } else {        props.children = children    }    return {        //$$--唯一性,jsx转换成为的类型        $$typeof: REACT_ELEMENT,        type,        ref,//操作DOM        key,//diff比拟        props    }}const React = {    createElement}export default React

4.ReactDOM.render函数编写

初始化渲染第一步:实现函数React.createElement
初始化渲染第二步:实现函数ReactDOM.render

react-dom.js

import { REACT_ELEMENT } from './utils'//初始化渲染(不止挂载操作)function render(VNode, containerDOM) {    // 将虚构DOM转化成实在DOM    // 将失去的实在DOM挂载到contanerDOM中    mount(VNode, containerDOM)}function mount(VNode, containerDOM) {    let newDOM = createDOM(VNode)    newDOM && containerDOM.appendChild(newDOM)}function createDOM(VNode) {    // 1.依据类型创立元素 2.解决子元素,VNode是树形构造 3.解决属性值    const { type, props } = VNode    let dom;    //typeof === REACT_ELEMENT代表虚构DOM VNode    if (type && VNode.$$typeof === REACT_ELEMENT) {        dom = document.createElement(type)    }    if (props) {        //子节点存在        if (typeof props.children === 'object' && props.children.type) {            //递归,创立子节点            mount(props.children, dom)        } else if (Array.isArray(props.children)) {            //多个子节点            mountArray(props.children, dom)        } else if (typeof props.children === 'string') {            //文本节点            dom.appendChild(document.createTextNode(props.children))        }    }    // TODO:解决属性值    //setPropsForDOM(dom, props)    return dom}//多个子节点解决function mountArray(children, parent) {    console.log('parent', parent, children)    if (!Array.isArray(children)) return    for (let i = 0; i < children.length; i++) {        if (typeof children[i] === 'string') {            //创立文本节点            parent.appendChild(document.createTextNode(children[i]))        } else {            mount(children[i], parent)        }    }}const ReactDOM = {    render}export default ReactDOM

5.实现函数setPropsForDOM进行属性更新

// 【这里须要留神jsx属性名称的写法】

ReactDOM.render(<div className='test-class' style={{color: 'red'}}>Simple React App<span>xx1</span><span>xx2</span></div>, document.getElementById('root'))
function setPropsForDOM(dom, VNodeProps = {}) {    if (!dom) return    for (let key in VNodeProps) {        if (key === 'children') continue        //^结尾,on结尾,A-Z之间一个,.匹配单个字符,        //*号匹配一个字母或者数字呈现一次或者屡次 onclick        if (/^on[A-Z].*/.test(key)) {            // TODO: 事件处理        } else if (key === 'style') {            Object.keys(VNodeProps[key]).forEach(styleName => {                dom.style[styleName] = VNodeProps[key][styleName]            })        } else {            dom[key] = VNodeProps[key]        }    }}

最初总结:从JSX源代码(<div>Hello JSX</div>)到显示到界面上,须要经验哪些关键环节。
JSX -> 转译成函数调用 -> 执行函数调用返回虚构DOM -> 将虚构DOM转化成DOM -> 将生成的DOM挂载到DOM上