响应式系统 | 青训营笔记

99 阅读2分钟

这是我参与「第四届青训营」笔记创作活动的的第 11 天

响应式编程设计

UI 编程的痛点

  • 当状态更新的时候,UI 不会自动更新,需要手动地调用 DOM 更新 UI。
  • 欠缺基本的代码层面的封装和隔离吗,代码层面没有组件化。
  • UI 之间的数据依赖关系,需要手动维护,如果依赖链路长,则会遇到回调地狱。

响应式与转换式

转换式系统:给定一个输入,求解输出。典型的转换式系统有:编译器和数值计算的程序。

响应式系统:监听事件,消息驱动。典型的响应式系统有:监控系统,UI 界面。

而我们的前端 UI 开发其实就是一个响应式的系统:触发事件、执行既定的回调、状态变更、更新 UI。

前端响应式 UI 系统

  • 状态更新 UI 自动更新。
  • 前端代码组件化,可复用,可封装。
  • 状态之间的互相依赖关系,只需要声明即可。

组件化设计

  • 组件声明了状态和 UI 的映射。
    • 输入状态,返回 UI。
  • 组件有 props 和 state 两种状态。
    • props 由辅助间传递而来,state 是组件自身的状态。
  • 组件可以由其他组件拼装而成。

状态归属问题

多个组件如果要使用同一个状态,那么这个状态必须放在这些组件的公共父组件上

如果组件嵌套比较深,最好是通过状态管理库来统一管理状态,而不是通过组件之间的嵌套来一层层传递状态。

React 的实现

  1. JSX 不符合 JS 的标准语法。

    • 使用 babel 等工具进行转译。
  2. 返回的 JSX 发生改变时,如何更新 DOM。

    • Virtual DOM + diff 算法,每次只更新不同的部分对应的真实 DOM 。
  3. state/props 更新时,要重新触发 render 函数。

Virtual DOM

Virtual DOM 是一种用于和真实 DOM 同步,而在 JS 内存中维护的一个对象,它具有和 DOM 类似的树状结构,并可以和 DOM 建立一一对应的关系。

如何 diff?

由于 render 函数的执行不能太慢,因此 diff 不能太多,而 diff 少的话就会导致不能算出最小的差别,导致需要更新更多的真实 DOM。

因此需要从 更新次数少计算速度快 之间权衡,选择一个合适的 diff 算法。

完美的最小 diff 算法,复杂度为 O(n3)O(n^3) 。Heuristic O(n) 算法牺牲了理论最小 diff,换取时间,得到了 O(n)O(n) 复杂度的算法。

这个算法的规则有三条:

  • 遇到不同类型的元素:替换元素
  • 遇到同类型的 DOM 元素:更新元素
  • 遇到同类型的组件元素:递归