状态管理 V1 和 V2 触发 UI 更新状态管理 V1 使用代理观察数据创建状态变量时会同时创建一个代理观察者该观察者可以感知代理变化但无法精准观测到实际数据变化。状态管理 V2 增强了数据的观察能力使数据本身可观察更新数据时会触发相应视图的更新。特性状态管理 V1状态管理 V2独立于 UI状态变量不能独立于 UI状态变量独立于 UI更新数据会触发相应视图的更新深度观测无法深度观测和深度监听只能感知对象属性第一层的变化支持对象的深度观测和深度监听且不影响观测性能精准更新更新对象中属性时存在冗余更新的问题支持对象中属性级精准更新易用性装饰器间配合使用限制多不易用不利于组件化装饰器易用性高、拓展性强有利于组件化状态管理的更新机制状态管理原理介绍状态管理的核心逻辑是处理状态变量、自定义组件和系统组件之间的绑定关系。状态管理循环执行两大步骤收集依赖和触发更新收集与状态变量绑定的组件标识当状态变量发生变化时对收集的组件执行标 “脏”刷新对应的 UI同时更新依赖观察状态管理的基本流程如图收集依赖收集依赖是指建立状态变量与组件之间的数据绑定关系。一个 UI 界面可能使用了多个状态变量在修改状态变量时仅与其相关的组件进行 UI 刷新其他不相关的组件不会刷新。因此UI 的刷新需要明确哪些组件使用了被修改的状态变量以实现这些组件的精准刷新。每个状态变量中都维护了一个 Set 集合保存所有与其绑定的组件的标识信息 (系统组件的唯一标识 elementId)即框架收集依赖的过程【示例】EntryComponentstruct Index{Stateage:number10;Stategrade:number5;build(){Column(){Text(age is: this.age)// Text1Text(grade is: this.grade)// Text1Button(change age)// Button1.onClick((){this.age;})Button(change grade)// Button2.onClick((){this.grade;})}}}上述示例Index 中定义了两个状态变量 age 和 grade框架收集依赖的步骤为调用 build 方法创建自定义组件 Index执行到Text(age is: this.age)时为了显示文本内容需要读取 this.age 的值 (Text2 同理)age 和 grade 都是 State 装饰的状态变量其在被读取时会收集当前正在渲染的系统组件的唯一标识 elementId并将其存储到状态变量维护的 Set 集合中触发更新当状态变量发生改变时状态管理框架会通知所有依赖于它的 UI 组件重新计算并刷新此过程称为触发更新。触发更新可分为三个步骤计算状态变量发生改变后的新值修改状态变量的值并将与其绑定的组件标脏刷新所有标脏的节点更新 UI 的同时重新收集依赖更新是以自定义组件为单位的每个自定义组件中维护了一个标脏的系统组件集合用于保存在当前 UI 更新周期中标脏的系统组件的 elementId即需要刷新的组件标识触发更新就是当状态变量发生改变时将其收集到的依赖组件标记为“脏”在下一个 UI 更新周期中只刷新标脏的组件实现最小化更新。同样对上述示例代码点击 Button 组件修改状态变量对应的 Text 组件刷新具体步骤为在点击事件中处理this.age由于 age 是状态变量在改值的过程中会执行状态管理内部的更新操作在状态变量 age 的更新操作中将其依赖集合中系统组件的 elementId 加入到其所属自定义组件 Index 的脏系统组件集合中 (每个自定义组件中维护了一个标脏的系统组件集合用于保存在当前 UI 更新周期中标脏的系统组件的 elementId)完成系统组件标脏后将状态变量 age 所属的自定义组件 Index 标脏加入到标脏的自定义组件节点列表中 (脏自定义组件列表)并请求一个刷新信号 (Vsync 信号)在下一个 UI 更新周期中 (下一个帧信号)框架遍历脏自定义组件列表重新调用其rerender方法 (rerender 方法是由系统生成的)遍历自定义组件 Index 中的脏系统组件刷新 Text 组件并更新依赖状态管理 V1 和 V2 的更新机制差异相比于 V1 状态管理状态管理 V2 在状态变量变化时会异步标脏组件如下图V1组件的更新步骤1事件触发修改 V1 状态变量观察状态变量的变化步骤2执行 Watch 回调步骤3执行节点标脏将脏节点放在脏节点列表中并请求Vsync信号步骤4更新脏节点列表先更新父组件再更新子组件步骤5若状态变量再次发生变化会执行步骤4步骤4在一个 Vsync 周期内的迭代不会超过 3 次第 3 次迭代后标脏的节点只会加到脏节点列表等下一个 Vsync 进行脏节点更新V2组件的更新V2 状态管理相比 V1新增异步执行 ComputedMonitor 和 节点标脏步骤1事件触发修改 V2 状态变量抛Promise异步任务步骤2等待事件的逻辑处理完成后 (如 onClick 事件)执行步骤1抛出的 Promise 回调步骤3执行 Computed 变量更新步骤4若 Computed 回调中有状态变量的变化回到步骤3否则进入步骤5步骤5执行 Monitor 回调函数步骤6若 Monitor 回调中有状态变量的变化则进入步骤3否则进入步骤7步骤7执行节点标脏将脏节点放在脏节点列表中并请求Vsync信号步骤8更新脏节点列表先更新父组件再更新子组件 (同 V1 组件的更新一个 Vsync 周期内迭代不会超过 3 次)V1 状态变量的变化会触发 Watch 的同步执行若状态变量被修改多次则 Watch 回调会同步执行多次V2 状态变量的变化会触发 Monitor 的异步执行若在一次事件中状态变量被多次修改Monitor 回调只会执行一次