首先感谢崔学社
经过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