手写 Mini React:从 0 实现 createElement 和 render,理解 React 的底层原理

在学习 React 的过程中,很多人都会有几个疑问:

  • JSX 为什么可以写在 JavaScript 里面?
  • React 的 Virtual DOM 到底是什么?
  • React 为什么不直接操作 DOM?
  • React 渲染 UI 的流程是怎样的?

如果只是使用 useStateuseEffect 等 API,很难真正理解 React 的核心设计。

最好的学习方式其实是:自己实现一个 Mini React

React 官方教程中有一个经典项目叫 Didact,它是一个极简版 React,用几十行代码实现 React 的核心机制。

本文将通过实现一个简单的 Mini React,理解 React 的核心流程:

sql 复制代码
JSX
 ↓
createElement
 ↓
Virtual DOM
 ↓
render
 ↓
Real DOM

通过这个过程,你会更清晰地理解 React 的底层原理。


一、React 的核心思想

现代前端框架(React / Vue)普遍遵循一种架构模式:

MVVM

sql 复制代码
Model(数据)
   ↓
ViewModel(框架)
   ↓
View(DOM)

开发者只需要关注 数据和业务逻辑,DOM 的创建、更新和销毁都由框架处理。

React 的核心思想可以总结为一句话:

用 JavaScript 描述 UI

例如传统 DOM 写法:

ini 复制代码
const div = document.createElement("div")
div.innerText = "Hello"
document.body.appendChild(div)

React 写法:

css 复制代码
<div>Hello</div>

React 会把 UI 转换成一种 JavaScript 数据结构,再由框架生成真实 DOM。


二、JSX 的本质

很多初学者会认为 JSX 是 HTML,但实际上 JSX 只是 JavaScript 的语法糖

例如:

javascript 复制代码
const element = <h1>Hello</h1>

经过 Babel 编译后会变成:

csharp 复制代码
const element = React.createElement("h1", null, "Hello")

所以 JSX 最终都会转换成一个函数调用:

scss 复制代码
createElement(type, props, children)

这也是 React 最核心的 API。


三、实现 createElement

接下来我们实现一个简化版 createElement

typescript 复制代码
function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === "object"
          ? child
          : createTextElement(child)
      )
    }
  }
}

这个函数返回的是一个 Virtual DOM 对象

例如:

css 复制代码
<div>Hello</div>

会被转换成:

css 复制代码
{
  type: "div",
  props: {
    children: [
      {
        type: "TEXT_ELEMENT",
        props: {
          nodeValue: "Hello",
          children: []
        }
      }
    ]
  }
}

可以看到,Virtual DOM 本质上只是普通 JavaScript 对象


四、为什么需要 TEXT_ELEMENT

在真实 DOM 中,其实存在两种节点:

scss 复制代码
Element Node
Text Node

例如:

css 复制代码
<div>Hello</div>

DOM 结构实际上是:

less 复制代码
div
 └── textNode("Hello")

为了统一处理节点结构,React 会把文本也包装成一个对象。

arduino 复制代码
function createTextElement(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: []
    }
  }
}

这样所有节点都会变成统一的数据结构:

bash 复制代码
{
  type,
  props
}

这也是 Virtual DOM 设计的重要原因:
统一数据结构,方便后续算法处理。


五、实现 render(VDOM → DOM)

现在我们已经得到了 Virtual DOM,接下来要把它转换成真实 DOM。

实现一个 render 函数:

ini 复制代码
function render(element, container) {
  const dom =
    element.type === "TEXT_ELEMENT"
      ? document.createTextNode("")
      : document.createElement(element.type)

  const isProperty = key => key !== "children"

  Object.keys(element.props)
    .filter(isProperty)
    .forEach(name => {
      dom[name] = element.props[name]
    })

  element.props.children.forEach(child =>
    render(child, dom)
  )

  container.appendChild(dom)
}

这个函数主要完成三件事情。

1 创建 DOM 节点

javascript 复制代码
document.createElement()
document.createTextNode()

如果是普通节点就创建 Element,如果是文本节点就创建 TextNode


2 设置属性

css 复制代码
dom[name] = element.props[name]

例如:

ini 复制代码
<h1 id="title">

最终会变成:

ini 复制代码
dom.id = "title"

3 递归渲染子节点

DOM 本身是树结构:

css 复制代码
div
 ├─ h1
 └─ h2

所以必须递归创建子节点:

ini 复制代码
element.props.children.forEach(child =>
  render(child, dom)
)

最终整个 Virtual DOM 树都会被转换成真实 DOM。


六、完整 Mini React 使用

最后导出 API:

ini 复制代码
window.Didact = {
  createElement,
  render
}

就可以写 JSX:

javascript 复制代码
/** @jsxRuntime classic */
/** @jsx Didact.createElement */

const element = (
  <div style="background:salmon">
    <h1>Hello, world!</h1>
    <h2 style="text-align:right">from Didact</h2>
  </div>
)

const container = document.getElementById("root")
Didact.render(element, container)

浏览器最终生成真实 DOM:

xml 复制代码
<div style="background:salmon">
  <h1>Hello, world!</h1>
  <h2 style="text-align:right">from Didact</h2>
</div>

至此,我们已经完成了一个最简单的 Mini React


七、React 为什么需要 Virtual DOM?

很多人认为 Virtual DOM 的目的就是"更快",其实并不完全准确。

Virtual DOM 的真正价值在于:

  • 抽象 UI
  • 可预测更新
  • 方便比较差异

React 会通过 Diff 算法 对比新旧 Virtual DOM:

复制代码
旧 VDOM
   vs
新 VDOM

只更新发生变化的部分,从而减少真实 DOM 操作。

例如:

css 复制代码
旧
<li>A</li>
<li>B</li>

新
<li>A</li>
<li>C</li>

React 只会更新:

css 复制代码
B → C

而不是重新创建整个列表。


八、总结

通过实现一个 Mini React,我们可以清晰地看到 React 的核心流程:

sql 复制代码
JSX
 ↓
createElement
 ↓
Virtual DOM
 ↓
render
 ↓
Real DOM

整个过程本质上就是:

用 JavaScript 对象描述 UI,再转换成真实 DOM。

当然,真正的 React 还包含很多复杂机制,例如:

  • Diff 算法
  • Fiber 架构
  • Hooks
  • 组件系统
  • 并发渲染

但所有这些能力,都是建立在 Virtual DOM 这一核心思想之上

理解了这个过程,再去阅读 React 源码,就会容易很多。

相关推荐
我命由我123454 小时前
前端开发 - this 指向问题(直接调用函数、对象方法、类方法)
开发语言·前端·javascript·vue.js·react.js·html5·js
Olafur_zbj5 小时前
【AI】深度解析OpenClaw智能体循环(Agentic Loop):底层运行机制、ReAct演进与多智能体协同架构
人工智能·react.js·架构·agent·openclaw
我命由我123455 小时前
React - ref、回调 ref 回调执行次数的问题、createRef 函数、事件处理
前端·javascript·react.js·前端框架·html·html5·js
我命由我123455 小时前
React - 收集表单元素、收集表单元素优化、生命周期(旧)、生命周期(新)
前端·javascript·react.js·前端框架·html·html5·js
We་ct5 小时前
JSX & ReactElement 核心解析
前端·react.js·面试·架构·前端框架·reactjs·个人开发
无巧不成书02185 小时前
React Native 深度解析:从架构到实战
react native·react.js·架构
汤姆Tom6 小时前
我把 Vue Router 搬到了 React —— 从 API 到文件路由、转场动画,一个都不少
前端·react.js·面试
无巧不成书02186 小时前
React Native 深度解析:跨平台移动开发框架(2026实战版)
javascript·react native·react.js
用户5757303346246 小时前
从 0 到 1 手写 React(part1):揭秘 MVVM 框架的“心脏”跳动原理
react.js