简单的mini-react基本搭建

1. dom节点渲染

const dom  = document.createElement('div')
dom.id = 'app'

const textNode = document.createTextNode('')
textNode.nodeValue = 'Hello world'
dom.append(textNode)

const container = document.querySelector("#app")
container.append(dom)

由上图可知,一个dom节点需要type,props,children。掌握这一层,下边一些API的实现就是基于它去演化的。

我们都了解react的children是存入props中的,为了方便访问和传递,组件复用,以及通过将children存入props中,可以支持树状结构的组件嵌套。并且将children转化为数组,可以处理多个子元素的情况。通过将子元素转化为数组,我们可以轻松地对子元素进行遍历、筛选、映射等操作,从而实现更灵活的组件组合方式。

// 创建dom节点
function createElement(type,props,...children) {
    return {
        type,
        props:{
            ...props,
            children
        }
    }
}

2. react搭建的Api的引用

import { ReactDom } from "./core/ReactDom.js"
import App from "./App.js"

ReactDom.createRoot(document.querySelector("#app")).render(App)
// 创建dom节点
function createElement(type,props,...children) {
    return {
        type,
        props:{
            ...props,
            children:children.map(child => {
                return typeof child === 'string' ? createTextNode(child) : child
            }) 
        }
    }
}

function render(el,container) {
    console.log(el);
    const { type,props } = el
    const dom = type === 'TEXT_ELEMENT' ? document.createTextNode("") : document.createElement(type)
    if(props) {
        Object.keys(props).forEach(key => {
            if(key !== 'children') {
                dom[key] = props[key]
            }
        })  
        props.children.forEach(child => {
            render(child,dom)
        })
    }
    container.append(dom)
}

function createTextNode(text) {
    return {
        type:'TEXT_ELEMENT',
        props:{
            nodeValue: text,
            children:[]
        }
    }
}

const React = {
    createElement,
    render
}

export default React
import React from "./React.js"
export const ReactDom =  {
    createRoot(container) {
        return {
            render(App){
                React.render(App,container)
            }
        }
    }
}

由于react的原理其实就是一个vdom,也就是一个js对象。将我们定义的type,props,children通过createElement转化为虚拟节点,然后调用render函数,通过type定义dom,然后循环props的key值,key值为children时采用循环递归处理,最后将其挂载到容器上。

3. 了解了基本的dom渲染以及api的引用。我们就可以通过命令进行框架的一个搭建,并且使用JSX文件

采用npm create vite创建项目

将原先的App.js,main.js复制过去,将其改为jsx后缀。发现并没有造成什么影响。并且我们在App.jsx里可以去除React.createElement的调用,直接写成标签,发现如果不调用craeteElement,页面依然可以正常渲染。其实是编译时会自动将其转化并且调用我们的React.createElement函数。

import React from "./core/React.js"

// const App = React.createElement('div',null,'123')
// 编译会自己调用React.createElement
const App = <div>hello world</div>
export default App

以上就是我们对mini-react的基本搭建。