React
背景
React 是 Meta(Facebook) 开发的一种用于 Web 和原生用户界面的库,同时也是一种架构(architecture)。2013年,Meta 宣布开源 React,设计者是 Jordan Walke。
2011年起,Meta 的开发者开始遇到一些代码维护(code maintenance)问题。随着 Meta 广告应用的功能越来越多,开发团队需要的人力也越多,越来越多的团队成员和应用程序功能,导致应用中存在大量关联更新,难以维护。React 主要目的就是为了解决当时代码维护问题,现在也是。
设计思想
- 组件化,组合优于继承。每个组件都符合开放-封闭原则,封闭是针对渲染工作流来说的,指的是组件只处理自身内部的渲染逻辑。开放是针对组件通信来说的,指的是不同组件可以通过 props(单向数据流)进行数据交互。
- 数据驱动视图,UI=f(data),如果要渲染界面,不应该直接操作 DOM,而是通过修改数据(props 或 state),由数据驱动视图更新。纯组件可以看作是种纯函数。
视图更新
主要分为两个阶段:渲染(render)和提交(commit)。
渲染阶段,通过协调(Reconciler)、diff,根据新旧虚拟 DOM(Virtual DOM,一种用 JavaScript 对象映射实际 DOM 的概念)变化,计算出必要的更新。
提交阶段,React 将渲染阶段计算出的更新应用于实际 DOM。包括增删改 DOM 节点。
React 设计虚拟 DOM 目的是避免不必要的 DOM 操作(DOM API 调用),且在不断改进虚拟 DOM 带来的性能问题。
- React 15前,采用递归遍历整个虚拟 DOM 树,缺点是比对耗时长,不能中断。
- React 16引入 fiber(一种数据结构,是由整个虚拟 DOM 树比对任务拆成的一个个更小的可执行的任务单元),采用循环遍历 fiber 链表,可随时中断,可放在主线程空闲时。
-
React 18引入新并发渲染器。该渲染器提供了一些将某些渲染任务标记为低优先的办法。当渲染低优先级组件时,每执行完一个 fiber 更新,就把控制权交还给 React 任务调度模块,看有没有更重要的任务等待处理,有则优先处理,从而提高用户交互体验。此外,并发渲染器还能在后台同时渲染组件树的多个版本,且无需立即提交。
具体实现时使用 userTransition 钩子提供的 startTransition 函数,将某些更新标记为过渡(Transitions),表示非紧急,可以被推迟或中断。在过渡开始时,并发渲染器会在后台准备新树,一旦完成渲染,它会将结果保留在内存中,等待提交。
setState 合并
将此次更新的优先级关联到当前 fiber 节点和根 fiber 节点,执行调度函数,调度函数会先判断当前应用根节点的优先级和当前已被调度的优先级是否相等。相等,是同一个函数下面的 setState,可以合并更新;不相等,发起协调任务,不相等分为两种情况,一种是首次发起调度,一种是高优先级任务进来。
调度 Scheduler
主要负责 React 的任务调度,其中包括分片调度和优先级调度。
分片调度的主要任务是负责渲染阶段能够间断执行节点遍历任务,优先级调度主要是为了将 React 任务划分为多种优先级类型,能够实现高优先级任务快速响应。
content
content 工作方式类似 CSS 属性继承。
生命周期
表示组件实例从创建到销毁的系列过程。
- 挂载
- 更新,组件的 props 或 state 变化时触发更新。组件是反应式的,而不是状态本身,这意味着不管是否触及状态,都可能运行状态计算代码。
- 卸载
函数式编程 Hooks
提升可组合性和可读性。
事件机制
React 所有的事件绑定在 container 上,react 17之前是固定 document。类似 DOM 的事件委托。
文章参考