从mini-react到面试题01:实现最简mini-react

原生js怎么写?

javascript 复制代码
const dom = document.createElement("div")
dom.id="app"
document.querySelector('#root').append(dom)

const textNode = document.createTextNode("")
textNode.nodeValue = "app"
dom.append(textNode)

为什么需要虚拟dom?

通过以上原生写法可以看出,虚拟dom可以简化开发,使代码更加框架、结构化,清晰可读易于维护。

框架层面:频繁的dom操作会一直导致浏览器重排和重绘,会严重影响性能。

原生层面:相对于原生层面虚拟dom对性能提示微乎其微,并且在复杂情况会损耗性能。

当然虚拟dom还有个非常重要的作用就是跨端运行。

面试怎么答?

  • 减少浏览器重排和重绘(框架层面、原生层面)
  • 跨平台运行,不局限于浏览器
  • 减少心智负担,提高开发效率

当然不能干巴巴的把这几点甩出去,记得拓展。

极简版React内核

此处代码实现了一个极简的创建虚拟dom和虚拟dom转真实dom

/core/React.js

javascript 复制代码
//创建文本对象虚拟dom
function createTextNode(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: [],
    },
  };
}

//创建虚拟dom对象
function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map((child) => {
        return typeof child === "string" ? createTextNode(child) : child;
      }),
    },
  };
}

//渲染器,vdom->tdom
function render(el, container) {
  const dom =
    el.type === "TEXT_ELEMENT"
      ? document.createTextNode("")
      : document.createElement(el.type);

  // id class
  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;

可以看到以上代码中createElement函数就实现了一个极简版的虚拟dom,里面有三个元素分别是:

  • type:类型
  • props:传入的值
  • children:子节点

render函数则实现了一个极简版的渲染器,用于将虚拟dom转化成真实dom,传入的值分别是:

  • el:虚拟dom对象
  • container:具体在哪个真实dom节点渲染

创建虚拟dom对象

/App.js

通过上面定义的createElement函数来创建一个虚拟dom对象app并将其导出

typescript 复制代码
import React from './core/React.js';
const App = React.createElement("div", { id: "app" }, "hi- ", "mini-react");
export default App

极简React渲染组件

定义了一个createRoot函数,通过传入的渲染容器container和虚拟dom对象App来将虚拟dom元素渲染到真实dom上。

/core/ReactDom.js

typescript 复制代码
import React from "./React.js";
const ReactDOM = {
  createRoot(container) {
    return {
      render(App) {
        React.render(App, container);
      },
    };
  },
};

export default ReactDOM;

创建ReactDOM

/main.js

javascript 复制代码
import ReactDOM from "./core/ReactDom.js";
import App from "./App.js";

ReactDOM.createRoot(document.querySelector("#root")).render(App);

总结

createRoot用于将虚拟dom渲染成真实dom

createElement用于创建虚拟dom对象

rendercreateRoot的内核

项目总结构:

markdown 复制代码
v01
├─ 📁core
│  ├─ 📄React.js
│  └─ 📄ReactDom.js
├─ 📄App.js
├─ 📄index.html
└─ 📄main.js

贴上main.js

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <div id="root"></div>
  <script type="module" src="main.js"></script>
</body>

</html>
相关推荐
yqzyy1 分钟前
Nginx 配置:alias 和 root 的区别
前端·javascript·nginx
冰糖雪梨dd6 分钟前
【JavaScript】 substring()方法详解
开发语言·前端·javascript
John Song12 分钟前
npm查看全局安装了哪些命令
前端·npm·node.js
清汤饺子20 分钟前
用了大半年 Claude Code,我总结了 16 个实用技巧
前端·javascript·后端
mCell7 小时前
【短文】不是最强,是最适合
前端·aigc·deepseek
余瑜鱼鱼鱼8 小时前
HTML常用标签总结
前端·html
Jave21088 小时前
Vue 中 mixins 混合开发的主要使用场景有哪些?
前端·vue.js
徐同保8 小时前
openclaw安装
前端
JEECG低代码平台9 小时前
JeecgBoot低代码平台 Ant Design Vue 4.x 升级避坑指南
前端·vue.js·低代码
yashuk9 小时前
Go-Gin Web 框架完整教程
前端·golang·gin