这是我参与「第四届青训营」笔记创作活动的的第 11 天
响应式编程设计
UI 编程的痛点
- 当状态更新的时候,UI 不会自动更新,需要手动地调用 DOM 更新 UI。
- 欠缺基本的代码层面的封装和隔离吗,代码层面没有组件化。
- UI 之间的数据依赖关系,需要手动维护,如果依赖链路长,则会遇到回调地狱。
响应式与转换式
转换式系统:给定一个输入,求解输出。典型的转换式系统有:编译器和数值计算的程序。
响应式系统:监听事件,消息驱动。典型的响应式系统有:监控系统,UI 界面。
而我们的前端 UI 开发其实就是一个响应式的系统:触发事件、执行既定的回调、状态变更、更新 UI。
前端响应式 UI 系统
- 状态更新 UI 自动更新。
- 前端代码组件化,可复用,可封装。
- 状态之间的互相依赖关系,只需要声明即可。
组件化设计
- 组件声明了状态和 UI 的映射。
- 输入状态,返回 UI。
- 组件有 props 和 state 两种状态。
- props 由辅助间传递而来,state 是组件自身的状态。
- 组件可以由其他组件拼装而成。
状态归属问题
多个组件如果要使用同一个状态,那么这个状态必须放在这些组件的公共父组件上。
如果组件嵌套比较深,最好是通过状态管理库来统一管理状态,而不是通过组件之间的嵌套来一层层传递状态。
React 的实现
-
JSX 不符合 JS 的标准语法。
- 使用 babel 等工具进行转译。
-
返回的 JSX 发生改变时,如何更新 DOM。
- Virtual DOM + diff 算法,每次只更新不同的部分对应的真实 DOM 。
-
state/props 更新时,要重新触发 render 函数。
Virtual DOM
Virtual DOM 是一种用于和真实 DOM 同步,而在 JS 内存中维护的一个对象,它具有和 DOM 类似的树状结构,并可以和 DOM 建立一一对应的关系。
如何 diff?
由于 render 函数的执行不能太慢,因此 diff 不能太多,而 diff 少的话就会导致不能算出最小的差别,导致需要更新更多的真实 DOM。
因此需要从 更新次数少 与 计算速度快 之间权衡,选择一个合适的 diff 算法。
完美的最小 diff 算法,复杂度为 。Heuristic O(n) 算法牺牲了理论最小 diff,换取时间,得到了 复杂度的算法。
这个算法的规则有三条:
- 遇到不同类型的元素:替换元素
- 遇到同类型的 DOM 元素:更新元素
- 遇到同类型的组件元素:递归