从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>
相关推荐
晨辰星6615 分钟前
Vue2中使用Echarts
前端·javascript·echarts
CodeToGym21 分钟前
三分钟在你的react项目中引入tailwindcss
前端·react.js·前端框架·tailwindcss
时间sk29 分钟前
CSS——10.类选择器
前端·css
我真不会起名字啊31 分钟前
QtJson数据格式处理详解
java·前端·javascript
【D'accumulation】1 小时前
基于 Node.js 的 ORM(对象关系映射)工具——Sequelize介绍与使用,并举案例分析
前端·javascript·学习·node.js·express
一个处女座的程序猿O(∩_∩)O1 小时前
vue3 如何封装aixos
前端·javascript·vue.js
YaHuiLiang2 小时前
小微互联网公司与互联网创业公司的技术之殇 - "新"技术的双刃剑
前端·后端·架构
桃园码工2 小时前
3_TypeScript 运算符 --[深入浅出 TypeScript 测试]
前端·javascript·typescript
low神2 小时前
Flutter面试题、Dart面试题
前端·javascript·flutter·react native·dart·前端面试题
风月歌2 小时前
基于Web的足球青训俱乐部管理后台系统的设计与开发源码(springboot+mysql+vue)
java·前端·spring boot·后端·mysql·mybatis·源码