整体架构流程图
graph TD
A["ReactDOM.createRoot(container)"] --> B["创建 RootDOMRoot 实例"]
B --> C["root.render(jsx)"]
C --> D["updateContainer(children, containerInfo)"]
D --> E["createFiber(children, returnFiber)"]
E --> F{判断节点类型}
F -->|"isStr(type)"| G["HostComponent
原生标签"] F -->|"isFn(type) && !isReactComponent"| H["FunctionComponent
函数组件"] F -->|"isFn(type) && isReactComponent"| I["ClassComponent
类组件"] F -->|"isUndefined(type)"| J["HostText
文本节点"] F -->|"其他 (Fragment)"| K["Fragment
空标签"] G --> L["scheduleUpdateOnFiber(rootFiber)"] H --> L I --> L J --> L K --> L L --> M["设置 wip = fiber, wipRoot = fiber"] M --> N["requestIdleCallback(workloop)"] N --> O["workloop 开始循环"] O --> P["performUnitOfWork()"] P --> Q{检查 wip.tag} Q -->|"HostComponent"| R["updateHostComponent(wip)"] R --> R1["创建 DOM 元素
document.createElement(type)"] R1 --> R2["updateNode(stateNode, props)
设置属性"] R2 --> R3["reconcileChildren(wip, props.children)"] Q -->|"FunctionComponent"| S["updateFunctionComponent(wip)"] S --> S1["调用函数组件
children = type(props)"] S1 --> S2["reconcileChildren(wip, children)"] Q -->|"ClassComponent"| T["updateClassComponent(wip)"] T --> T1["实例化类组件
instance = new type(props)"] T1 --> T2["调用 render 方法
children = instance.render()"] T2 --> T3["reconcileChildren(wip, children)"] Q -->|"HostText"| U["updateTextComponent(wip)"] U --> U1["创建文本节点
document.createTextNode(text)"] Q -->|"Fragment"| V["updateFragmentComponent(wip)"] V --> V1["reconcileChildren(wip, props.children)
直接处理子节点"] R3 --> W["遍历子节点创建 Fiber"] S2 --> W T3 --> W V1 --> W W --> X["深度优先遍历
如果有 child,继续处理"] X --> Y{是否还有 wip?} Y -->|"有"| P Y -->|"无"| Z["commitRoot(wipRoot)"] Z --> AA["commitWork(fiber)"] AA --> BB["递归提交所有节点"] BB --> CC{检查 flags} CC -->|"Placement"| DD["appendChild 到父节点"] CC -->|"其他"| BB DD --> EE["渲染完成"] style A fill:#e1f5fe style G fill:#fff3e0 style H fill:#e8f5e8 style I fill:#fce4ec style J fill:#f3e5f5 style K fill:#fff8e1 style EE fill:#e8f5e8
原生标签"] F -->|"isFn(type) && !isReactComponent"| H["FunctionComponent
函数组件"] F -->|"isFn(type) && isReactComponent"| I["ClassComponent
类组件"] F -->|"isUndefined(type)"| J["HostText
文本节点"] F -->|"其他 (Fragment)"| K["Fragment
空标签"] G --> L["scheduleUpdateOnFiber(rootFiber)"] H --> L I --> L J --> L K --> L L --> M["设置 wip = fiber, wipRoot = fiber"] M --> N["requestIdleCallback(workloop)"] N --> O["workloop 开始循环"] O --> P["performUnitOfWork()"] P --> Q{检查 wip.tag} Q -->|"HostComponent"| R["updateHostComponent(wip)"] R --> R1["创建 DOM 元素
document.createElement(type)"] R1 --> R2["updateNode(stateNode, props)
设置属性"] R2 --> R3["reconcileChildren(wip, props.children)"] Q -->|"FunctionComponent"| S["updateFunctionComponent(wip)"] S --> S1["调用函数组件
children = type(props)"] S1 --> S2["reconcileChildren(wip, children)"] Q -->|"ClassComponent"| T["updateClassComponent(wip)"] T --> T1["实例化类组件
instance = new type(props)"] T1 --> T2["调用 render 方法
children = instance.render()"] T2 --> T3["reconcileChildren(wip, children)"] Q -->|"HostText"| U["updateTextComponent(wip)"] U --> U1["创建文本节点
document.createTextNode(text)"] Q -->|"Fragment"| V["updateFragmentComponent(wip)"] V --> V1["reconcileChildren(wip, props.children)
直接处理子节点"] R3 --> W["遍历子节点创建 Fiber"] S2 --> W T3 --> W V1 --> W W --> X["深度优先遍历
如果有 child,继续处理"] X --> Y{是否还有 wip?} Y -->|"有"| P Y -->|"无"| Z["commitRoot(wipRoot)"] Z --> AA["commitWork(fiber)"] AA --> BB["递归提交所有节点"] BB --> CC{检查 flags} CC -->|"Placement"| DD["appendChild 到父节点"] CC -->|"其他"| BB DD --> EE["渲染完成"] style A fill:#e1f5fe style G fill:#fff3e0 style H fill:#e8f5e8 style I fill:#fce4ec style J fill:#f3e5f5 style K fill:#fff8e1 style EE fill:#e8f5e8
1. 渲染入口阶段
1.1 创建根容器
javascript
// src/react-dom.js
function createRoot(container) {
const root = {
containerInfo: container,
};
return new RootDOMRoot(root);
}
1.2 触发渲染
javascript
// src/react-dom.js
RootDOMRoot.prototype.render = function (children) {
const { containerInfo } = this._internalRoot;
updateContainer(children, containerInfo);
};
function updateContainer(children, containerInfo) {
const rootFiber = createFiber(children, {
type: containerInfo.nodeName.toLowerCase(),
stateNode: containerInfo,
});
scheduleUpdateOnFiber(rootFiber);
}
2. Fiber 节点创建与类型识别
2.1 组件类型判断逻辑
javascript
// src/ReactFiber.js
export function createFiber(vnode, returnFiber) {
const fiber = {
type: vnode.type,
key: vnode.key,
props: vnode.props,
stateNode: null,
child: null,
sibling: null,
return: returnFiber,
flags: Placement,
index: null,
alternate: null,
};
// 判断 tag,确定 fiber 任务节点类型
const { type } = vnode;
if (isStr(type)) {
// 原生标签:div, span, h1 等
fiber.tag = HostComponent;
} else if (isFn(type)) {
// 函数组件、类组件
fiber.tag = type.prototype.isReactComponent
? ClassComponent // 类组件
: FunctionComponent; // 函数组件
} else if (isUndefined(type)) {
// 文本节点
fiber.tag = HostText;
fiber.props = { children: vnode };
} else {
// Fragment 空标签
fiber.tag = Fragment;
}
return fiber;
}
2.2 组件类型常量定义
javascript
// src/ReactWorkTags.js
export const FunctionComponent = 0;
export const ClassComponent = 1;
export const HostComponent = 5;
export const HostText = 6;
export const Fragment = 7;
3. 工作循环与调度
3.1 调度入口
javascript
// src/ReactFiberWorkLoop.js
export function scheduleUpdateOnFiber(fiber) {
wip = fiber; // work in progress
wipRoot = fiber; // work in progress root
}
3.2 时间切片工作循环
javascript
// src/ReactFiberWorkLoop.js
function workloop(deadline) {
// 判断浏览器空闲时间是否可以执行任务
while (wip && deadline.timeRemaining() > 1) {
performUnitOfWork();
}
if (!wip && wipRoot) {
commitRoot(wipRoot);
}
}
// 使用浏览器空闲时间
requestIdleCallback(workloop);
3.3 工作单元处理
javascript
// src/ReactFiberWorkLoop.js
function performUnitOfWork() {
const { tag } = wip;
// 根据组件类型分发处理函数
switch (tag) {
case HostComponent:
updateHostComponent(wip);
break;
case HostText:
updateTextComponent(wip);
break;
case ClassComponent:
updateClassComponent(wip);
break;
case FunctionComponent:
updateFunctionComponent(wip);
break;
case Fragment:
updateFragmentComponent(wip);
break;
default:
break;
}
// 深度优先遍历
if (wip.child) {
wip = wip.child;
return;
}
let next = wip;
while (next) {
if (next.sibling) {
wip = next.sibling;
return;
}
next = next.return;
}
wip = null;
}
4. 各组件类型的具体处理
4.1 🟢 函数组件渲染流程
javascript
// src/ReactFiberReconciler.js
export function updateFunctionComponent(wip) {
const { type, props } = wip;
// 直接调用函数组件获取子元素
const children = type(props);
// 协调子节点
reconcileChildren(wip, children);
}
特点:
- ✅ 直接函数调用,性能高效
- ✅ 无实例化开销
- ❌ 不支持生命周期方法
- ❌ 不创建 DOM 节点
4.2 🔴 类组件渲染流程
javascript
// src/ReactFiberReconciler.js
export function updateClassComponent(wip) {
const { type, props } = wip;
// 1. 实例化类组件
const instance = new type(props);
// 2. 调用 render 方法获取子元素
const children = instance.render();
// 3. 协调子节点
reconcileChildren(wip, children);
}
类组件基类:
javascript
// src/ClassComponent.js
function Component(props) {
this.props = props;
}
// 区分函数组件与类组件的标识
Component.prototype.isReactComponent = {};
特点:
- ✅ 支持生命周期方法
- ✅ 支持实例方法和状态
- ❌ 实例化开销较大
- ❌ 不创建 DOM 节点
4.3 🟡 Fragment 渲染流程
javascript
// src/ReactFiberReconciler.js
export function updateFragmentComponent(wip) {
// 直接处理子节点,不创建包装 DOM
reconcileChildren(wip, wip.props.children);
}
特点:
- ✅ 透明容器,不产生额外 DOM
- ✅ 可以返回多个子元素
- ✅ 避免不必要的 DOM 嵌套
- ❌ 不能接收除 children 外的 props
4.4 🔵 原生标签渲染流程
javascript
// src/ReactFiberReconciler.js
export function updateHostComponent(wip) {
// 1. 创建 DOM 元素
if (!wip.stateNode) {
const stateNode = document.createElement(wip.type);
wip.stateNode = stateNode;
}
// 2. 更新节点属性
updateNode(wip.stateNode, wip.props);
// 3. 协调子节点
reconcileChildren(wip, wip.props.children);
}
4.5 🟣 文本节点渲染流程
javascript
// src/ReactFiberReconciler.js
export function updateTextComponent(wip) {
const { props } = wip;
const text = props.children;
// 创建文本节点
wip.stateNode = document.createTextNode(text);
}
5. 子节点协调机制
5.1 reconcileChildren 函数
javascript
// src/ReactFiberReconciler.js
function reconcileChildren(wip, children) {
// 跳过字符串和数字类型的直接子节点
if (isStringOrNumber(children)) {
return;
}
let newFiber = null;
let previousNewFiber = null;
// 确保 children 是数组
let arr = Array.isArray(children) ? children : [children];
// 为每个子元素创建 Fiber 节点
for (let i = 0; i < arr.length; i++) {
newFiber = createFiber(arr[i], wip);
if (previousNewFiber === null) {
// 第一个子节点
wip.child = newFiber;
} else {
// 建立兄弟节点链表
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
}
}
5.2 Fiber 树结构
php
父 Fiber
├── child ──→ 第一个子 Fiber
├── sibling ──→ 第二个子 Fiber
├── sibling ──→ 第三个子 Fiber
└── return ──→ 父 Fiber
6. 深度优先遍历策略
6.1 遍历逻辑
javascript
// 深度优先遍历 (国王的故事)
if (wip.child) {
// 优先处理子节点
wip = wip.child;
return;
}
let next = wip;
while (next) {
if (next.sibling) {
// 处理兄弟节点
wip = next.sibling;
return;
}
// 回到父节点
next = next.return;
}
wip = null; // 遍历完成
6.2 遍历示例
css
A
/ \
B C
/ \ /
D E F
遍历顺序:A → B → D → E → C → F
7. 提交阶段 (Commit Phase)
7.1 提交入口
javascript
// src/ReactFiberWorkLoop.js
function commitRoot(wipRoot) {
commitWork(wipRoot);
wipRoot = null;
}
7.2 DOM 操作提交
javascript
// src/ReactFiberWorkLoop.js
function commitWork(fiber) {
if (!fiber) {
return;
}
const { flags, stateNode } = fiber;
let parentNode = getParentNode(fiber);
// 根据 flags 执行相应的 DOM 操作
if (flags === Placement && stateNode) {
parentNode.appendChild(stateNode);
}
// 递归提交子节点和兄弟节点
commitWork(fiber.child);
commitWork(fiber.sibling);
}
function getParentNode(fiber) {
let next = fiber.return;
while (next) {
if (next.stateNode) {
return next.stateNode;
}
next = next.return;
}
}
8. 组件类型对比总结
特性 | 函数组件 | 类组件 | Fragment | 原生标签 | 文本节点 |
---|---|---|---|---|---|
DOM 创建 | ❌ | ❌ | ❌ | ✅ | ✅ |
执行方式 | 直接调用 | 实例化 + render | 透传子节点 | createElement | createTextNode |
性能开销 | 低 | 中 | 最低 | 低 | 最低 |
生命周期 | ❌ | ✅ | ❌ | ❌ | ❌ |
状态管理 | Hooks | this.state | ❌ | ❌ | ❌ |
使用场景 | 无状态 UI | 复杂逻辑 | 避免嵌套 | 实际 DOM | 纯文本 |
9. 核心设计理念
9.1 Fiber 架构优势
- 可中断渲染:支持时间切片,避免长时间阻塞主线程
- 优先级调度:可以根据任务重要性调整执行顺序
- 错误边界:更好的错误处理和恢复机制
9.2 组件设计原则
- 单一职责:每种组件类型专注于特定功能
- 组合优于继承:通过组合实现复杂 UI
- 声明式编程:描述"是什么"而非"怎么做"
9.3 性能优化策略
- 函数组件:适用于简单 UI,减少实例化开销
- 类组件:适用于复杂逻辑,支持完整生命周期
- Fragment:避免不必要的 DOM 嵌套,提升渲染性能
10. 实际使用示例
10.1 组件定义
javascript
// 函数组件
function FunctionComponent(props) {
return (
<div className="border">
<p>{props.name}</p>
{props.children}
</div>
);
}
// 类组件
class ClassComponent extends Component {
render() {
return (
<div className="border">
<h3>{this.props.name}</h3>
我是文本
</div>
);
}
}
// Fragment 使用
function FragmentComponent() {
return (
<ul>
<>
<li>part1</li>
<li>part2</li>
</>
</ul>
);
}
10.2 渲染调用
javascript
const jsx = (
<div className="border">
<h1>react</h1>
<FunctionComponent name="函数组件">
<span>子组件</span>
</FunctionComponent>
<ClassComponent name="类组件" />
<>
<div>Fragment 内容</div>
</>
</div>
);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(jsx);