- 初始渲染
- React会将整个组件树转换为一个大的react元素【虚拟DOM】 -虚拟DOM
- 一个由组件树中所有实例创建的所有react元素的树
- 相对便宜和快速,即使需要多次迭代【最终也只是一个JavaScript对象】
- react渲染组件时,会导致该组件所有子组件同时被渲染【无论传递的props是否改变】
- 当应用程序中某个位置的状态发生变化时,只需更新DOM的一小部分即可,重用DOM已经存在的其余部分
- React会在shouldComponentUpdate生命周期方法中判断组件是否需要重新渲染
- Fiber
- 初始渲染时,获取整个React元素树【虚拟DOM】
- 基于虚拟DOM,创建Fiber树,对于应用程序中每个组件实例和DOM元素都有一个fiber
- fiber不会在每次渲染时重新创建【永远不会被摧毁】
- 相反fiber是一个可变的数据结构,在渲染初期被创建,在未来的协调步骤中一次又一次的发生变化
- 组件实例的实际状态和属性都存储在fiber树种相应的fiber内部,fiber树包含工作队列
- fiber还是一个工作单元,工作可以异步进行
- 协调
- 决定需要插入、删除或更新那些DOM元素,以反映最新的stats更改
- 协调由协调器处理【协调器实际上是react引擎】
- 元素在元素树中的位置一步步比较【差分】
- 当虚拟DOM重新渲染后,与Fiber树的比较过程生成一个“Fiber树更新”或“协调更新”的结构,记录了对Fiber节点的各种变更
- 提交阶段,由ReactDOM实现
- 差分算法
- Reconciliation(协调)阶段:
- 深度优先遍历: React使用深度优先遍历策略遍历两颗Fiber树,找到差异节点。
- 比较节点类型: 对于每个节点,首先比较它们的类型(函数组件、类组件、原生DOM节点等)。
- Key属性: 如果节点有key属性,React会使用key来匹配相同类型的节点,以提高比较效率。【通过稳定的key,元素可以保留在DOM中,即使树中的位置发生了变化】
- 更新、插入、删除操作: 根据对比结果,确定更新、插入和删除节点的操作。
- Commit(提交)阶段:
- 生成副作用链表: 在协调阶段得出的需要更新的节点会形成一个副作用链表(Effect List)。
- Commit阶段的深度优先遍历: React再次使用深度优先遍历策略,实际地操作DOM并执行生命周期方法。
- 执行生命周期方法: 在commit阶段,React执行组件的生命周期方法,比如componentDidMount等。
- 实际DOM操作: 对于每个节点,React执行实际的DOM操作,比如更新文本内容、添加/删除DOM节点等。
- Reconciliation(协调)阶段:
初始渲染:
React应用启动时,会进行初始渲染。在这个阶段,React会创建虚拟DOM(Virtual DOM)树,该树是一个轻量级的JavaScript对象表示整个UI结构。
同时,React会构建Fiber树,Fiber是一种用于表示和处理组件树的数据结构,它支持增量渲染和异步更新。
组件更新触发:
当组件的状态或属性发生变化时,React会触发更新。这可能是由用户交互、网络请求或其他事件引起的。
调和(Reconciliation):
React使用调和算法来确定虚拟DOM中哪些部分需要更新。调和的目标是通过最小化DOM操作来提高性能。
虚拟DOM树会与上一次渲染的Fiber树进行比较,找出需要更新的部分。
更新虚拟DOM:
通过调和算法,React找出需要更新的虚拟DOM节点。这些节点表示发生变化的组件及其子组件。
React会为这些发生变化的组件调用其 render 方法,得到新的虚拟DOM。
构建新的Fiber树:
基于新的虚拟DOM,React构建新的Fiber树。这个过程允许React支持异步渲染和中断。
协调(Commit):
在协调阶段,React将新的Fiber树中的变化“提交”到实际的DOM。这包括添加、更新和删除DOM节点。
此时,React会执行生命周期方法(如 componentDidUpdate)以及可能的副作用。
最终呈现到浏览器:
最终,变化会反映在浏览器中,用户看到更新后的UI。
- stats更新是批量的
- 多个stats更新不会立即导致每次更新都重新呈现,而是一次提交渲染
- stats更新在react中是异步的
- 如果要基于先前的状态更新更新状态,需要使用带有回调的setState【setAnswer(ans => ans = "")】
- 在react 18之前,如果函数被timeout,promise调用,函数内部的状态更新不会被批量更新
- 在函数中,打印stats的结果,会打印更新之前的值【因为异步】
- 事件触发时,在DOM树种创建一个新的事件对象【但是不在实际发生位置创建而是文档的根处document】,在捕获阶段沿着DOM树向下行进,直到到达目标元素【事件实际上第一次被触发的元素】
- 到达目标元素后,事件对象在冒泡阶段沿着DOM树向上返回
- 在捕获/冒泡阶段,会便利每个父元素和子元素
- 默认情况下,事件处理程序不仅监听目标元素上的事件,而且还在冒泡阶段监听,意味着父元素中每个事件处理程序也将在冒泡阶段执行,只要它也在监听相同类型的事件
React在设计上更注重组件化和声明式编程,而不是强制性地规定应用程序的整体架构,可以自由组合
- React提供了一种构建UI的灵活方式,允许开发人员根据项目的需要选择和组合不同的工具、库和模式
- React专注于解决构建用户界面的问题,如组件化、虚拟DOM等,而不涉及如何管理应用程序的其他方面,比如路由、状态管理等
- React本身相对来说比较轻量级,只提供了构建UI所需的核心功能,不像一些框架那样包含大量的预置功能和规范