ReactJS 中的 JSX工作原理

文章目录

  • 前言
    • [✅ 1. JSX 是什么?](#✅ 1. JSX 是什么?)
    • [🔧 2. 编译后的样子(核心机制)](#🔧 2. 编译后的样子(核心机制))
    • [🧱 3. `React.createElement` 做了什么?](#🧱 3. React.createElement 做了什么?)
    • [🧠 4. JSX 与组件的关系](#🧠 4. JSX 与组件的关系)
    • [🔄 5. JSX 到真实 DOM 的过程](#🔄 5. JSX 到真实 DOM 的过程)
    • [📘 6. JSX 与 Fragment、条件渲染等底层行为](#📘 6. JSX 与 Fragment、条件渲染等底层行为)
    • [⚠️ 7. 注意事项](#⚠️ 7. 注意事项)
    • [✅ 总结](#✅ 总结)
  • [JSX 编译后如何通过 Fiber 架构驱动渲染更新](#JSX 编译后如何通过 Fiber 架构驱动渲染更新)
    • [✅ 一、React 渲染整体流程概览(React 18+)](#✅ 一、React 渲染整体流程概览(React 18+))
    • [🧠 二、什么是 Fiber 架构?](#🧠 二、什么是 Fiber 架构?)
      • [📦 一个 Fiber 节点结构简化如下:](#📦 一个 Fiber 节点结构简化如下:)
    • [🔄 三、Reconciliation(协调 / diff)机制](#🔄 三、Reconciliation(协调 / diff)机制)
      • [Diff 规则核心简化:](#Diff 规则核心简化:)
    • [⚙️ 四、Commit 阶段(更新真实 DOM)](#⚙️ 四、Commit 阶段(更新真实 DOM))
    • [⏱️ 五、Concurrent Mode(React 18)](#⏱️ 五、Concurrent Mode(React 18))
      • [🌟 调度示意(非阻塞渲染):](#🌟 调度示意(非阻塞渲染):)
    • [📌 六、双缓冲机制(双 Fiber Tree)](#📌 六、双缓冲机制(双 Fiber Tree))
    • [🎯 七、性能优化的启示](#🎯 七、性能优化的启示)
    • [✅ 总结:JSX 到 DOM 的底层机制主线](#✅ 总结:JSX 到 DOM 的底层机制主线)
  • [⏱️ React Fiber 调度与中断机制:时间切片、优先级调度、任务恢复](#⏱️ React Fiber 调度与中断机制:时间切片、优先级调度、任务恢复)
    • [✅ 1. 为什么需要中断渲染?](#✅ 1. 为什么需要中断渲染?)
    • [✅ 2. Fiber 如何解决这个问题?](#✅ 2. Fiber 如何解决这个问题?)
      • [🎯 利用:](#🎯 利用:)
    • [📦 3. 任务调度:Scheduler 的优先级系统](#📦 3. 任务调度:Scheduler 的优先级系统)
    • [⏳ 4. 时间切片机制(Time Slicing)](#⏳ 4. 时间切片机制(Time Slicing))
    • [🔁 5. 中断与恢复机制](#🔁 5. 中断与恢复机制)
    • [⚙️ 6. Concurrent 模式的核心优势](#⚙️ 6. Concurrent 模式的核心优势)
    • [🧠 7. 示例:startTransition 与中断渲染](#🧠 7. 示例:startTransition 与中断渲染)
    • [✅ 8. 总结:Fiber 调度机制的精髓](#✅ 8. 总结:Fiber 调度机制的精髓)
    • [📘 延伸(可选深入)](#📘 延伸(可选深入))

前言

ReactJS 中的 JSX(JavaScript XML)看起来像 HTML,但它其实只是语法糖,在底层是被编译成 React.createElement(...) 调用的 JavaScript 代码。理解其底层机制对优化性能、调试问题、使用 Hooks 等非常重要。


✅ 1. JSX 是什么?

JSX 是 JavaScript 的语法扩展,允许你这样写 UI:

js 复制代码
const element = <h1>Hello, world!</h1>;

它看起来像 HTML,但不是。它不会被浏览器直接执行,而是会在构建阶段被转译为 JavaScript。


🔧 2. 编译后的样子(核心机制)

这段代码:

js 复制代码
const element = <h1 className="title">Hello</h1>;

会被 Babel 编译为:

js 复制代码
const element = React.createElement(
  'h1',
  { className: 'title' },
  'Hello'
);

等价于:

js 复制代码
{
  type: 'h1',
  props: {
    className: 'title',
    children: 'Hello'
  }
}

最终,React 用这些对象来构建虚拟 DOM(Virtual DOM)。


🧱 3. React.createElement 做了什么?

它会返回一个React 元素对象

js 复制代码
{
  $$typeof: Symbol(react.element),
  type: 'h1',
  key: null,
  ref: null,
  props: {
    className: 'title',
    children: 'Hello'
  },
  _owner: null
}

这是一个纯 JS 对象,描述了 UI 的结构。不是 DOM 节点,还没有真正渲染。


🧠 4. JSX 与组件的关系

JSX 中也可以使用组件:

js 复制代码
<MyButton text="Click me" />

被编译为:

js 复制代码
React.createElement(MyButton, { text: "Click me" });

最终调用你自己写的 MyButton(props) 函数,返回另一个 createElement(...)


🔄 5. JSX 到真实 DOM 的过程

  1. JSX 被编译为 React.createElement(...)
  2. React 构建虚拟 DOM 树
  3. React 将虚拟 DOM diff(比对)旧的 DOM 树
  4. React 使用 DOM API 更新真实 DOM(插入、删除、替换节点)

📘 6. JSX 与 Fragment、条件渲染等底层行为

  • <></>React.createElement(React.Fragment, null, ...)
  • 条件渲染:{condition && <div>Yes</div>} → 三元或逻辑判断
  • 循环渲染:{list.map(item => <li>{item}</li>)} → 多次 createElement 调用

⚠️ 7. 注意事项

特性 底层意义
JSX 只能有一个根节点 因为 React.createElement 只能返回一个元素
不支持 if 语句直接写在 JSX JSX 是表达式,需要用三元或外部逻辑
自闭和标签 <MyComp /> 转译为 React.createElement(MyComp)
不能直接渲染对象 [object Object] 错误是因为 createElement 接收了非法 children

✅ 总结

概念 作用
JSX React 的语法糖,用来描述 UI 结构
Babel 把 JSX 编译为 React.createElement()
React.createElement 创建虚拟 DOM 描述对象
虚拟 DOM 一个 JS 对象树,最终映射为真实 DOM
渲染机制 Diff + 更新 DOM 节点(最小化操作)

JSX 编译后如何通过 Fiber 架构驱动渲染更新

这一主线,系统讲解 React 的底层工作机制,包括:


✅ 一、React 渲染整体流程概览(React 18+)

graph TD A[JSX] --> B[createElement] B --> C[构建虚拟 DOM] C --> D[Fiber 架构构建 Fiber Tree] D --> E[Reconciliation(diff)] E --> F[Commit 阶段:更新真实 DOM]

🧠 二、什么是 Fiber 架构?

Fiber 是 React 从 v16 开始的核心架构,其主要目标是:

  • 支持任务中断(可暂停)
  • 支持异步渲染(并发模式)
  • 增强调度控制
  • 支持优先级(Urgent、Normal、Idle)

Fiber = 一种"工作单元"结构,用链表组织虚拟 DOM,便于逐个处理、可打断、可恢复


📦 一个 Fiber 节点结构简化如下:

ts 复制代码
interface Fiber {
  type: string | FunctionComponent
  stateNode: HTMLElement | null
  child: Fiber | null
  sibling: Fiber | null
  return: Fiber | null
  alternate: Fiber | null // 双缓存机制
  effectTag: 'UPDATE' | 'PLACEMENT' | 'DELETION'
}

🔄 三、Reconciliation(协调 / diff)机制

目的:比较新旧 virtual DOM,找到最小变更,生成 effectList 用于更新真实 DOM。

Diff 规则核心简化:

  • 同层比较:只比较同级节点
  • Key 区分同类型组件:用于 map 渲染性能优化
  • 类型不同 → 全替换
  • 类型相同 → 尝试复用

⚙️ 四、Commit 阶段(更新真实 DOM)

当 Fiber 树构建完毕后,进入 commit 阶段:

ts 复制代码
// commitWork
switch (fiber.effectTag) {
  case 'PLACEMENT': // 插入
    parent.appendChild(fiber.stateNode);
    break;
  case 'UPDATE': // 属性或内容变更
    updateDOM(fiber.stateNode, oldProps, newProps);
    break;
  case 'DELETION':
    parent.removeChild(fiber.stateNode);
    break;
}

⏱️ 五、Concurrent Mode(React 18)

React 18 引入并发渲染模式,依赖 Fiber 实现:

特性 描述
startTransition 标记可中断更新(非紧急)
自动批处理 setState 自动分组,不再需要 unstable_batchedUpdates
useDeferredValue 延迟非关键状态同步更新
useTransition 标记 UI "pending" 状态,支持 loading skeleton 等过渡体验
ReactDOM.createRoot 默认进入 Concurrent 模式

🌟 调度示意(非阻塞渲染):

js 复制代码
startTransition(() => {
  setValue(input);
})

React 会调度优先级高的操作(如输入)先渲染,低优先的任务稍后处理。


📌 六、双缓冲机制(双 Fiber Tree)

React 使用 currentworkInProgress 两棵 Fiber Tree,交替使用:

current 正在显示的 UI
workInProgress 当前计算的新状态

当 Reconciliation 完成,React 会"交换"两棵树,实现 快照切换


🎯 七、性能优化的启示

场景 原因 优化策略
大量列表重复渲染 Key 设计不当导致全部 diff 用稳定 Key
卡顿严重 所有状态更新同步 使用 startTransition, useDeferredValue
多组件嵌套,重渲染过多 props 未 memo 使用 React.memouseMemo, useCallback
复杂条件渲染 JSX 重计算多 使用懒加载 React.lazy, Suspense

✅ 总结:JSX 到 DOM 的底层机制主线

阶段 关键内容
编译 JSX → createElement → 虚拟 DOM
构建 Fiber 树结构,链表连接
diff Reconciliation 识别变化
更新 commit 阶段执行 effect list 操作真实 DOM
并发 Fiber 允许中断、恢复、优先级调度
优化 利用 Hook + memo + key + transition

⏱️ React Fiber 调度与中断机制:时间切片、优先级调度、任务恢复

React Fiber 架构最大的突破之一就是它将渲染任务拆分为"工作单元"(Fiber 节点),并使用浏览器的空闲时间或非阻塞方式来执行这些任务。


✅ 1. 为什么需要中断渲染?

问题:

React 早期(v15 及以前)渲染是同步的:

js 复制代码
ReactDOM.render(<App />, root);

如果组件树很大,JS 线程会被"卡死",导致:

  • 输入卡顿
  • 动画掉帧
  • 无法响应用户操作

✅ 2. Fiber 如何解决这个问题?

🧠 核心思想:把渲染拆成很多小任务,用浏览器空闲时间分批执行,并可中途暂停与恢复。

🎯 利用:

ts 复制代码
requestIdleCallback(callback)

或(React 18 起)用:

ts 复制代码
scheduler.unstable_scheduleCallback(priority, callback)

📦 3. 任务调度:Scheduler 的优先级系统

React 使用内部调度器(scheduler)给任务分配优先级:

调度级别 描述 示例
Immediate (最高) 立刻执行 setState 同步
UserBlocking 用户操作相关 输入、点击
Normal 默认更新 内容变化
Low 非关键 动画、日志
Idle 不重要 预加载

⏳ 4. 时间切片机制(Time Slicing)

Fiber 会把任务拆成一个个 unit of work,然后循环调度:

ts 复制代码
while (nextUnitOfWork && shouldYield() === false) {
  nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}

shouldYield() 检查是否要让位给浏览器,防止掉帧。

ts 复制代码
function shouldYield() {
  return performance.now() >= deadline;
}

🔁 5. 中断与恢复机制

如果 shouldYield()true,Fiber 会 中断当前工作 ,然后把当前状态保存在 workInProgress 上,下次从这个点继续:

ts 复制代码
// workInProgress 保存当前 fiber 的指针链表状态

浏览器空闲后,React 会再次调度:

ts 复制代码
requestIdleCallback(workLoop)

⚙️ 6. Concurrent 模式的核心优势

能力 说明
✋ 中断 渲染过程可被暂停
🔁 恢复 下一帧继续渲染剩余部分
⚖️ 优先级 用户输入优先渲染,非关键可延后
🎨 更流畅 输入不卡顿,动画更自然
🧠 更智能 可实现并行 diff、预渲染、Suspense fallback 等功能

🧠 7. 示例:startTransition 与中断渲染

ts 复制代码
import { startTransition } from 'react'

function handleInput(e) {
  const value = e.target.value

  // 非紧急更新,允许中断
  startTransition(() => {
    setFilteredList(filterBigList(value))
  })
}

用户打字不会因为 setFilteredList() 而卡顿,因为这是一个"可中断更新"。


✅ 8. 总结:Fiber 调度机制的精髓

内容
拆分 Fiber 把渲染任务拆成小单元
调度 使用 scheduler 或 requestIdleCallback 进行执行调度
中断 shouldYield() 决定是否让步给浏览器主线程
恢复 保存中间状态于 Fiber,支持恢复渲染
优先级 按任务重要程度进行排序调度,保障交互流畅性

📘 延伸(可选深入)

如果你还想进一步了解:

  1. Lane Model(React 18 调度核心)
  2. React Scheduler 实现(源码级)
  3. Suspense + Fiber 如何协同暂停渲染树
  4. Concurrent Features:如 React.lazy, Streaming SSR
相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax