首先感谢崔学社
经过7天的学习跟着阿崔通过拆分任务,小步迭代,完成了一个mini-react,了解了Fiber、Reconcile等执行原理。
Day1
1. 实现最简 mini-react
在根目录下创建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>mini-react</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="main.js"></script>
</body>
</html>
根目录下
// /main.js
import ReactDom from "./core/ReactDom.js";
import App from "./App.js";
ReactDom.createRoot(document.querySelector("#root")).render(App);
根目录下
// /App.js
import React from "./core/React.js";
const App = React.createElement("div", { id: "app" }, "hello world");
export default App;
根目录下
// /core/React.js
function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children: children.map((child) => {
return typeof child === "string" ? createTextNode(child) : child;
}),
},
};
};
{
"type": "div",
"props": {
"id": "app",
"children": [
{
"type": "TEXT_ELEMENT",
"props": {
"nodeValue": "hello world",
"children": []
}
}
]
}
}
render接收两个参数,el是通过createElement创建出来的,container就是dom节点。
通过
循环将props中key的值,对应赋值给dom[key]。
单独处理children,递归处理子节点。
function render(el, container) {
const dom =
el.type === "TEXT_ELEMENT"
? document.createTextNode("")
: document.createElement(el.type);
Object.keys(el.props).forEach((key) => {
if (key !== "children") {
dom[key] = el.props[key];
}
});
const children = el.props.children;
children.forEach((child) => {
render(child, dom);
});
container.append(dom);
}
function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children: children.map((child) => {
return typeof child === "string" ? createTextNode(child) : child;
}),
},
};
};
function createTextNode(text) {
return {
type: "TEXT_ELEMENT",
props: {
nodeValue: text,
children: [],
},
};
};
function render(el, container) {
const dom =
el.type === "TEXT_ELEMENT"
? document.createTextNode("")
: document.createElement(el.type);
Object.keys(el.props).forEach((key) => {
if (key !== "children") {
dom[key] = el.props[key];
}
});
const children = el.props.children;
children.forEach((child) => {
render(child, dom);
});
container.append(dom);
}
const React = {
render,
createElement,
};
export default React;
根目录下
import React from "./React.js";
const ReactDom = {
createRoot(container) {
return {
render(App) {
return React.render(App, container);
},
};
},
};
export default ReactDom;
在根目录通过

到这里我们就实现了最简版本
2. 引入vite,使用JSX
在根目录下创建vite项目
pnpm create vite vite-runner --template vanilla
将之前的
将
// /vite-runner/main.jsx
import ReactDom from "./core/ReactDom.js";
import App from "./App.jsx";
ReactDom.createRoot(document.querySelector("#root")).render(App);
别忘了修改
... <div id="root"></div> <script type="module" src="/main.jsx"></script> ...
这样我们就可以通过vite启动项目了,别忘了在vite-runner下安装依赖
cd vite-runner pnpm dev
仓库地址:https://github.com/zhuzhux/mini-react