网站首页 > 技术文章 正文
好问题 你问的是 React Fiber 架构。这是 React 16 引入的核心机制,用来解决 React 在大规模更新时的性能问题。下面我给你从 背景 → Fiber 是什么 → 原理 → 优点 → 流程 来系统讲。
一、为什么需要 Fiber?
在 React 15 及以前,Reconciler(协调器) 是 递归调用 的:
- 一旦开始遍历虚拟 DOM 树,就会一直执行到更新完成。
 - JS 是单线程的,如果组件树很大,就会长时间阻塞 UI(比如用户输入、动画掉帧)。
 
React 16 引入 Fiber 架构,实现“可中断的渲染”。
二、Fiber 是什么?
- Fiber 既是数据结构,又是调度机制。
 
1. 数据结构(链表树)
- 旧的虚拟 DOM 是树形结构,Fiber 把它改造成 链表树。
 - 每个 Fiber 节点对应一个 React 组件,保存了:
 - type:组件类型(函数 / 类 / DOM 节点)
 - pendingProps / memoizedProps:新旧 props
 - stateNode:真实 DOM 或类组件实例
 - child / sibling / return:指向子节点、兄弟节点、父节点(让树可以“遍历暂停+恢复”)。
 
2. 调度机制
- Fiber 把渲染任务拆分成 小块(unit of work)。
 - 每完成一个小块,就检查是否有更高优先级的任务(比如用户输入)。
 - 如果有 → 暂停渲染,先去执行高优先级任务;之后再恢复渲染。
 
这就是所谓的 时间分片(Time Slicing)。
三、Fiber 的工作流程
React Fiber 的工作分 两大阶段:
1.调和阶段(Reconciliation / Render Phase)
- 生成新的 Fiber 树(虚拟 DOM → Fiber 节点)。
 - 可以被中断(异步执行)。
 - 做的事:
 - Diff 新旧 Fiber(比较新旧 props、state、子节点)。
 - 标记需要的更新(Placement / Update / Deletion)。
 
2.提交阶段(Commit Phase)
- 把 Fiber 树的变更同步到真实 DOM。
 - 不能中断(必须一次性完成)。
 - 分三步:
 - Before Mutation:调用 getSnapshotBeforeUpdate。
 - Mutation:操作 DOM(插入、更新、删除)。
 - Layout:执行生命周期钩子(componentDidMount / useLayoutEffect)。
 
四、Fiber 的优点
- 可中断渲染:解决 React 15 “一口气渲染完”的问题。
 - 优先级调度:不同更新任务有不同优先级(比如输入比动画更重要)。
 - 增量渲染:一次渲染可以拆成多次完成。
 - 为 Concurrent Mode(并发模式)打基础:React 18 的并发特性基于 Fiber。
 
五、Fiber 更新优先级(Scheduler)
Fiber 为每个更新任务分配优先级:
- Immediate:立即执行(比如点击)。
 - User-blocking:高优先级(比如输入)。
 - Normal:普通优先级。
 - Low:低优先级(比如数据预加载)。
 - Idle:空闲时才执行。
 
React 内部用 Scheduler(调度器) 来管理任务优先级。
六、整体流程总结
- 触发更新(setState / useState)。
 - 调度器接管 → 把更新放入任务队列。
 - 调和阶段(可中断):构建新的 Fiber 树,标记变更。
 - 提交阶段(不可中断):批量更新真实 DOM。
 - 渲染完成,用户看到更新。
 
七、类比理解
可以把 React Fiber 想象成:
- 旧版 React:写一篇长文章时,必须一次写完,不能停。
 - Fiber React:写文章时,每写几句就停下来,看看是不是有人找你聊(高优先级任务),聊完再继续写文章。
 
猜你喜欢
- 2025-09-18 大厂都在用 @tanstack/react-query
 - 2025-09-18 Vue和React迎来大融合!开发效率大提升
 - 2025-09-18 七爪源码:如何在 React 中删除元素 OnClick
 - 2025-09-18 通过番计时器实例学习 React 生命周期函数 componentDidMount
 - 2025-09-18 React组件渲染优化:掌握key prop的3个实战技巧
 - 2025-09-18 我找到了 Compiler 在低版本中使用的方法,它不再是 React 19 的专属
 - 2025-09-18 JavaScript Proxy与Reflect实战经验顿悟
 - 2025-09-18 React在开发中的常用结构以及功能详解
 - 2025-09-18 2025开发React+Flask全栈应用最佳实践:10万+开发者验证终极指南
 - 2025-09-18 快速上手React_快速上手 英文
 
- 最近发表
 - 
- 聊一下 gRPC 的 C++ 异步编程_grpc 异步流模式
 - [原创首发]安全日志管理中心实战(3)——开源NIDS之suricata部署
 - 超详细手把手搭建在ubuntu系统的FFmpeg环境
 - Nginx运维之路(Docker多段构建新版本并增加第三方模
 - 92.1K小星星,一款开源免费的远程桌面,让你告别付费远程控制!
 - Go 人脸识别教程_piwigo人脸识别
 - 安卓手机安装Termux——搭建移动服务器
 - ubuntu 安装开发环境(c/c++ 15)_ubuntu安装c++编译器
 - Rust开发环境搭建指南:从安装到镜像配置的零坑实践
 - Windows系统安装VirtualBox构造本地Linux开发环境
 
 
- 标签列表
 - 
- cmd/c (90)
 - c++中::是什么意思 (84)
 - 标签用于 (71)
 - 主键只能有一个吗 (77)
 - c#console.writeline不显示 (95)
 - pythoncase语句 (88)
 - es6includes (74)
 - sqlset (76)
 - apt-getinstall-y (100)
 - node_modules怎么生成 (87)
 - chromepost (71)
 - flexdirection (73)
 - c++int转char (80)
 - mysqlany_value (79)
 - static函数和普通函数 (84)
 - el-date-picker开始日期早于结束日期 (76)
 - js判断是否是json字符串 (75)
 - c语言min函数头文件 (77)
 - asynccallback (87)
 - localstorage.removeitem (77)
 - vector线程安全吗 (73)
 - java (73)
 - js数组插入 (83)
 - mac安装java (72)
 - 无效的列索引 (74)
 
 
