响应式编程
狭义: 面向数据串流和变化传播的声明式编程范式
RxJS:
- 事件: 观察者模式
- 序列: 迭代器模式
- 流: 管道模式
响应式数据。我们用 ref 或 reactive 创建的数据,可以等似于 RxJS 的 Observable。只不过响应式数据并不像 rxjs 有显式的事件发布和订阅过程,也不存在事件流(序列)。 Vue 数据的每次变更就相当于 RxJS 发出每次事件
衍生数据。我们会使用 computed 来衍生新的数据,等似于 RxJS 用操作符衍生出新的 Observable。 Vue 数据衍生数据,RxJS 事件衍生事件
副作用。在 Vue 中, watch/watcheffects/render 相当于 RxJS 的 subscribe,RxJS 的数据流的终点通常也是副作用处理,比如将数据渲染到页面上
思想转换: 管道变换: 把程序视作从输入到输出的一个变换去构思
不好的代码:
- 创建了大量的缓存状态。比如 sum,avg,temp…
- 使用了很多 watch / watchEffect…
- 冗长的 setup 方法或者组件代码
- 状态被随意修改,修改不属于管辖范围内的状态
大部分情况下, 组件表示是一个 UI 对象. 其实组件不单单可以表示 UI, 也可以用来抽象业务对象, 有时候抽象为组件可以巧妙地解决一些问题
原则和建议
- 优先使用 computed,警惕 watch/watchEffect 等 API 的使用。转换思维先从克制使用 watch 开始。
- 适当使用 readonly, 禁止状态被坏人修改
- 最小化状态。避免创建‘缓存’状态,让数据自然流动,不要阻断。
- 自顶而下,将细节/副作用分流到 hooks 或子组件中,起一个好一点的名字, 让流程看起来更清晰
- 将 watch 转换为 computed 的语义。外观上的差别是 watch 有 callback, 而 computed 是「管道」,会衍生新的数据。
- 推荐使用 VueUse
- 封装 hooks, 让各种外部的状态或副作用优雅地集成进来
- 单向数据流,对这个有两层理解
- 表示是一种数据流动的方向,通常和 CQRS 模式配合,比如 Redux、Vuex,只能单向的修改和查询
- 表示一种数据管辖的范围。 通常应用只有数据的拥有者才有权限变更。进一步地讲,我们应该以组件为边界,来限定数据的管辖范围。需要变更时,通过‘事件’ 来通知拥有者。比如 严格遵循 v-model 协议。
- 使用响应式开发思维,构造单向的数据流
- 尽量管道化的方式去设计你的程序
- 声明式,不要命令式
- 拆分组件或 hooks 来分治数据流
- 组件之间 props 传递也属于数据流
- 使用 ref/reactive → computed → watch → handler → render 这样的顺序组织代码