Appearance
React 原理篇
问题 1:虚拟 DOM 的意义
虚拟DOM是一种js对象 用来抽象描述真实DOM结构。
- 减少实际的 DOM 操作:通过比较新旧虚拟 DOM 树的差异,React 可以确定需要更新的部分,并生成最小化的 DOM 操作序列。这样可以减少实际的 DOM 操作次数,提高性能。
- 批量更新:React 会将所有需要更新的 DOM 操作批量执行,从而避免了频繁的 DOM 操作,提高了性能。
- 跨平台兼容性:虚拟 DOM 是一个轻量级的 JavaScript 对象,可以在不同的平台上运行,例如浏览器、移动设备和服务器。这使得 React 可以在多个环境中使用相同的代码和逻辑。
- 更好的开发体验:虚拟 DOM 使得开发者可以使用类似于 HTML 的标记语言来描述 UI,而不需要直接操作 DOM。这简化了开发过程,并提供了更好的开发体验。
问题 2:JSX 转为真实 DOM 的过程?
- jsx 代码:
jsx
return (
<div className="box">
{/* 组件 */}
<Header>hello</Header>
{/* 元素 */}
<div>container</div>
{/* 文本 */}
footer
</div>
);- 使用 Babel 将 jsx 转为 React.createElement 后:
React.createElement(type, props, ...children)
js
React.createElement(
"div",
{ className: "box" },
React.createElement(Header, null, "hello"),
React.createElement("div", null, "container"),
"footer"
);- 创建虚拟 DOM
React.createElement 返回一个描述 UI 的 JavaScript 对象(即虚拟 DOM)。
- 调用 ReactDOM.render
使用 ReactDOM.render 方法将虚拟 DOM 渲染到指定的挂载容器中。
js
ReactDOM.render(虚拟DOM, document.getElementById("root"));- Diff 算法比较差异
- React 使用高效的 Diff 算法来比较新旧虚拟 DOM 树之间的差异。
- 只更新有变化的部分,生成最小化的 DOM 操作序列。
- 批量更新与优化
React 会将所有需要更新的 DOM 操作批量执行,以减少实际的 DOM 操作次数,提高性能
- 生成真实 DOM
最终,React 将这些最小化的 DOM 操作应用到浏览器的真实 DOM 中,完成页面的渲染或更新。
问题 3:React DOM 的 diff 算法
React 的虚拟 DOM diff 算法是一种用于比较新旧虚拟 DOM 树的差异的算法,目标是找出需要更新的部分,并生成一个最小化的 DOM 操作序列:
- 比较根节点:算法首先比较新旧虚拟 DOM 树的根节点。如果它们的类型不同,那么 React 会完全替换旧的 DOM 树。如果它们的类型相同,那么算法会继续比较它们的属性和子节点。
- 比较属性:算法会比较新旧虚拟 DOM 树的属性,判断是否有属性发生了变化。如果有属性发生了变化,React 会更新对应的 DOM 节点上的属性。
- 比较子节点:算法会递归地比较新旧虚拟 DOM 树的子节点。如果子节点的数量不同,那么 React 会更新对应的 DOM 节点的子节点。如果子节点的数量相同,那么算法会继续比较它们的类型和内容。
- 递归比较:算法会递归地比较新旧虚拟 DOM 树的子节点。如果子节点的类型相同,那么算法会继续比较它们的属性和子节点。如果子节点的类型不同,那么 React 会完全替换旧的 DOM 节点。
- 生成 DOM 操作序列:通过比较新旧虚拟 DOM 树,算法会生成一个最小化的 DOM 操作序列,包括插入、更新和删除操作。React 会将这些操作批量执行,从而减少实际的 DOM 操作次数。
问题 4:Fiber 架构
React Fiber架构是React在16版本推出的一种全新的、革命性的调度算法和组件更新机制。它对React核心算法进行了重构,以满足更流畅的UI渲染、更灵活的任务调度以及更好的交互体验。
回答: 在旧版React中,React DOM diff 过程是一个递归的过程,会一直执行直到完成,期间无法中断。长时间js执行可能会阻塞主线程,造成页面卡顿和不流畅的用户体验。 Fiber 是一种新的架构,fiber即是一个数据结构,也是一个工作单元,它将渲染任务拆分为可中断恢复的工作单元,这个工作单元就是一个fiber对象,fiber对象通过parent subling child 去连接当前结构的父fiber 兄弟fiber和子fiber,这些可中断恢复的工作单元会在浏览器空闲时分片执行,从而避免主线程阻塞。内部采用双缓存机制,同时维护两颗fiber树,一颗是current fiber,代表当前ui的fiber树,一颗workinprogress树,代表后台正在构建的fiber树,当构建完成时会进行原子替换,这样减少了画面的撕裂感,提升了用户体验。
目的
Fiber 的目标是改进 React 的性能和用户体验,使得 React 应用程序更加流畅和响应。
- 解决主线程阻塞: 在 React 的旧版本中,虚拟 DOM diff 过程是一个递归的过程,它会一直执行直到完成,期间无法中断。这可能会导致长时间的 JavaScript 执行,从而阻塞主线程,造成页面的卡顿和不流畅的用户体验。
- 解决无法中断与恢复渲染: 为了解决这个问题,React 引入了 Fiber 架构。Fiber 将整个虚拟 DOM diff 过程分为多个小任务,每个任务称为一个 Fiber 节点。这些 Fiber 节点被组织成一个树状结构,称为 Fiber 树。
- Fiber 树可以被中断和恢复,这意味着在执行 Fiber 树的 diff 过程时,可以在任意时刻中断当前任务,并优先执行其他任务。这样可以使得应用程序更加灵活地响应用户的交互和其他优先级的任务,提高性能和响应性。
- 解决无法实现增量渲染: 通过 Fiber 架构,React 可以根据任务的优先级动态地调整任务的执行顺序,从而更好地控制 JavaScript 的执行。这使得 React 应用程序可以在不阻塞主线程的情况下进行虚拟 DOM diff,减少页面的卡顿和提高用户体验。
- 总而言之,Fiber 是 React 中一种新的架构,用于实现增量式的、可中断的虚拟 DOM diff 过程。它通过将 diff 过程分为多个小任务,并根据优先级动态地调整任务的执行顺序,提高 React 应用程序的性能和响应性。
问题 5: React渲染机制核心原理
渲染流程
- 触发更新
- 创建虚拟DOM:React 通过 JSX 语法创建虚拟 DOM。虚拟 DOM 是 React 中最核心的概念,它描述了 UI 的结构,但不包含任何实际的 DOM 元素。
- diff 算法:React 使用 diff 算法来比较当前虚拟 DOM 和上一次渲染的虚拟 DOM,并计算出最小的更新。
- 更新 DOM:React 根据 diff 结果,将最小的更新应用到实际 DOM 上。
- 渲染完成:React 渲染完成后,会调用 componentDidUpdate() 方法,并传入 prevProps 和 prevState 两个参数。
Reconciliation阶段: 当React决定要更新UI时,它会启动reconciliation(协调)过程。在这个阶段,React会比较新旧两棵树之间的差异,并为需要更新的组件生成相应的Fiber节点。这个过程是异步的,可以被中断和恢复。
Commit阶段: 当所有的Fiber节点都被处理完毕后,React会进入commit阶段。在这个阶段,React会将之前在render阶段计算出的所有变化一次性应用到DOM上,并触发相关的生命周期方法(如useEffect,useLayoutEffect方法)。这个过程是不可中断的,因为它涉及到实际的DOM操作。
优先级调度: React Fiber通过优先级调度来管理任务的执行顺序。每个Fiber节点都有一个与之关联的优先级,React会根据节点的优先级来决定哪些节点需要先更新。高优先级的任务(如用户交互)会打断低优先级的任务(如定时器回调)并优先执行,从而实现更流畅的用户体验。
协调策略
- 树对比:仅对比同层级节点,时间复杂度O(n)
- Key值优化:列表项使用key帮助React识别元素移动/复用
问题 6: 不同版本的React区别
主要
- React 16:
- fiber架构
- 错误边界
- Fragment
- Portals
- createContext
- React 17:
- 事件委托机制重写
- 引入新的jsx转换方法
- 生命周期废弃
- React 18:
- 并发模式:渲染中断、高优先级处理
- 自动批处理:多次渲染合并
- 新增hooks:
- useTransition: 延迟渲染部分组件,提升用户体验
- useDeferredValue: 延迟值更新,提升性能
- useId: 生成唯一ID,提升无障碍访问
