ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

【ArkUI进阶练中学】第1课:状态管理V2与深度观测

【ArkUI进阶练中学】第1课:状态管理V2与深度观测 本节目标理解状态管理 V1 在嵌套对象观测上的根本局限掌握 V2 深度观测的设计理念掌握ObservedV2与Trace的配合机制能够实现对嵌套类和继承类的属性级深度观测掌握 V2 组件装饰器ComponentV2、Local、Param、Once、Event的用法与约束掌握Monitor异步监听与Computed计算属性的使用理解 V2 监听能力的增强掌握 V1 到 V2 的迁移步骤与混用限制能够将 V1 项目中的嵌套状态逻辑重构为 V2 的深度观测方案一、V1 的观测局限与 V2 的设计动机1.1 V1 嵌套观测的根本问题在状态管理 V1 中State仅能观察对象的第一层属性变化。对于嵌套类对象属性变化无法被直接观测。以下代码点击后不会触发 UI 刷新ObservedclassSon{name:string;age:number;constructor(name:string,age:number){this.namename;this.ageage;}}ObservedclassFather{son:Son;constructor(name:string,age:number){this.sonnewSon(name,age);}}EntryComponentstruct Index{Statefather:FathernewFather(John,8);build(){Row(){Column(){Text(name:${this.father.son.name}age:${this.father.son.age}).fontSize(50).onClick((){this.father.son.age;// 不会触发 UI 刷新})}}}}V1 的解决方案是使用ObjectLink配合自定义组件将嵌套对象逐层拆解。这要求每一层都创建自定义组件并配上ObjectLink代码复杂度随嵌套深度线性增长。1.2 V2 的设计理念状态管理 V2 将观测能力实现在类属性层级而非组件层级。ObservedV2Trace提供了直接观测嵌套对象属性变化的能力无需逐层创建自定义组件。关键变化V1 中“组件层级配合实现深度观测”的模式被 V2 中“数据模型层面直接解决”的模式取代。当Trace装饰的属性变化时仅会通知该属性关联的组件进行刷新。二、ObservedV2 与 Trace 深度观测2.1 基本用法ObservedV2是类装饰器Trace是类属性装饰器两者必须配套使用单独使用任一装饰器均不生效。从 API version 12 开始支持。// 使用ObservedV2类装饰器使 Son 类具有深度观测能力ObservedV2classSon{// 使用Trace装饰器标记需要观测的属性属性变化时触发 UI 刷新Traceage:number100;}classFather{son:SonnewSon();}EntryComponentV2struct Index{father:FathernewFather();build(){Column(){Text(${this.father.son.age}).onClick((){this.father.son.age;// 自动触发 UI 刷新})}}}注意Father类没有被任何装饰器修饰但Text组件中使用this.father.son.age时age变化依然会自动刷新。这是因为Trace将观测能力实现在了Son.age属性上。2.2 嵌套类的观测规则在嵌套类中路径上的每一层对象都需要是可观察的。如果中间层是普通对象修改最深层字段时没有可追踪的Trace变更。嵌套类中的属性被Trace装饰且嵌套类被ObservedV2装饰时才具有触发 UI 刷新的能力。ObservedV2classAddress{Tracecity:string北京;}// 必须也加ObservedV2否则 address.city 的变化无法被观测ObservedV2classUser{Tracename:string张三;address:AddressnewAddress();}关键规则如果A持有BB的字段要被观测B本身必须是ObservedV2且字段加Trace。只给外层加是不够的。2.3 继承类的观测在继承类中父类或子类中属性的变化仅当属性被Trace装饰且所属类被ObservedV2装饰时才会触发 UI 刷新。ObservedV2classBase{TracebaseValue:number0;}ObservedV2classDerivedextendsBase{TracederivedValue:number0;}2.4 实例化约束被ObservedV2和Trace装饰的类必须使用new操作符实例化才具有变化观测能力。如果通过对象字面量等方式创建观测能力不会生效。2.5 与 V1 Track 的对应关系V1 的Track是精确观察装饰器不使用则无法做到类属性的精准观察。V2 的Trace装饰的属性可以被精确跟踪观察。V2 的Trace相当于 V1Track的升级版但 V2 不需要ObjectLink配合观测能力直接实现在类属性上。三、V2 组件状态管理装饰器3.1 ComponentV2ComponentV2是 V2 的自定义组件装饰器与 V1 的Component对应。V1 的自定义组件中不可以使用 V2 的装饰器否则编译报错。3.2 Local组件内部状态Local对应 V1 的State用于装饰组件内部的状态变量。关键差异简单类型可以直接将State替换为Local。复杂类型Local只能观察对象自身的变化引用替换不能观察对象内部属性的变化。如果需要追踪对象内部的属性变化必须结合ObservedV2和Trace。Local 禁止外部初始化V1 中State支持从外部传递初始值V2 中Local不允许。若需要从外部传递初始值使用Param和Once。ComponentV2struct Counter{Localcount:number0;// 简单类型直接替换 Statebuild(){Button(计数${this.count}).onClick((){this.count;})}}3.3 Param组件外部输入Param对应 V1 的Prop用于接收父组件传递的数据。Param是单向输入不建议在子组件中直接修改。当输入参数为复杂类型时Prop为深拷贝Param为引用。3.4 Once初始化同步一次Once用于Param表示该参数只在初始化时从父组件同步一次之后父组件的更新不再同步到子组件。3.5 Event规范组件输出Event用于规范组件的输出事件通常与Param配合实现父子组件双向同步。V1 的Link双向绑定拆成ParamEvent子组件发事件让父组件更新。ComponentV2struct Child{Paramval:number0;EventaddOne:()void;build(){Button(${this.val}).onClick((){this.addOne();})}}EntryComponentV2struct Parent{LocalmyVal:number0;build(){Child({val:this.myVal,addOne:()this.myVal})}}四、Monitor 与 Computed4.1 Monitor状态变量修改监听Monitor是 V2 的状态变量修改监听装饰器对应 V1 的Watch但能力更强。Monitor不仅能够感知变化后的数据还能获取变化前的数据。Monitor 不触发的排查首先确认组件必须是ComponentV2其次被监听的必须是状态变量、Trace属性或Computed最后ObservedV2实例要通过new创建且变化的字段必须加Trace。路径监听Monitor监听多个属性时需要写清楚路径。监听深层对象时要写完整路径如Monitor(user.address.city)。Monitor是异步合并触发——一次事件里多个属性连续变化通常只回调一次拿到最终状态。4.2 Computed计算属性Computed是 V2 新增的计算属性装饰器。V1 无计算属性相关能力V2 可使用Computed避免重复计算。在Computed中计算的状态变量被改变时计算属性会重新计算。关键规则Computed只有依赖的Local、Param、Trace等状态变化时才会触发 UI 重新计算和刷新。如果依赖的状态没有变化即使 UI 重新渲染计算属性也不会重新计算。使用建议对于简单计算不建议使用计算属性因为计算属性本身也有开销。五、V1 到 V2 迁移指南5.1 迁移策略新项目直接采用 V2。已有 V1 项目逐步迁移建议按“组件装饰器 → 数据模型 ObservedV2 化 → 存储方案”的顺序进行。5.2 迁移步骤第一步将Component替换为ComponentV2State替换为LocalProp替换为Param。第二步将Link双向绑定拆成ParamEvent。第三步将Observed替换为ObservedV2需要观测的属性加Trace嵌套类也要各自加ObservedV2。第四步将AppStorage迁移到AppStorageV2PersistentStorage迁移到PersistenceV2。5.3 V1/V2 混用限制V1 的自定义组件中不可以使用 V2 的装饰器否则编译报错。当组件间不传递变量时V1 的自定义组件中可以使用 V2 的自定义组件。ObservedV2和Observed嵌套使用时类对象能否被 V1 的装饰器装饰取决于最外层 class 使用的装饰器。六、多元化习题习题 1判断题题目在状态管理 V2 中ObservedV2装饰的类中未被Trace装饰的属性发生变化时UI 也会自动刷新。答案错误解读未被Trace装饰的属性无法被检测到变化不会触发 UI 刷新。只有被Trace装饰的属性变化才会触发关联组件的重新渲染。习题 2单选题题目以下哪个装饰器与ObservedV2配套使用标记类中需要被观测的属性A.ObjectLinkB.TraceC.MonitorD.Track答案B解读ObservedV2与Trace配套使用装饰类以及类中的属性。ObjectLink是 V1 的装饰器Monitor用于监听状态变量变化Track是 V1 的属性级精确观察装饰器。习题 3多选题题目关于 V2 的Local以下说法正确的有多选A.Local对应 V1 的State用于组件内部状态B.Local装饰的复杂对象可以自动观察其嵌套属性的变化C.Local禁止从外部传递初始值D. 需要从外部传递初始值时使用Param和Once答案A、C、D解读Local对应State用于组件内部状态选项 A 正确。Local只能观察对象自身的变化不能观察对象内部属性的变化选项 B 错误。Local禁止外部初始化选项 C 正确。需要外部传递初始值时使用Param和Once选项 D 正确。习题 4代码填空题题目请补全以下代码使User类的name属性变化时能够触发 UI 刷新。______________classUser{______________ name:string张三;age:number25;}答案ObservedV2、Trace解读ObservedV2装饰类使其具有深度观测能力Trace装饰需要被观测的属性。只有被Trace装饰的属性变化才会触发 UI 刷新age没有加Trace其变化不会触发 UI 刷新。习题 5代码改错题题目以下代码存在错误请指出问题并修正。ObservedV2classAddress{city:string北京;// 缺少装饰器}ObservedV2classUser{Tracename:string张三;address:AddressnewAddress();}EntryComponentV2struct Index{Localuser:UsernewUser();build(){Text(${this.user.address.city}).onClick((){this.user.address.city上海;// 不会触发 UI 刷新})}}答案Address类的city属性缺少Trace装饰器。修正如下ObservedV2classAddress{Tracecity:string北京;// 添加Trace装饰器}解读在嵌套类中属性被Trace装饰且嵌套类被ObservedV2装饰时才具有触发 UI 刷新的能力。Address类虽然被ObservedV2装饰但city属性未被Trace装饰因此变化无法被观测。习题 6简答题题目简述 V2 的ObservedV2Trace相比 V1 的ObservedObjectLink的核心优势。答案V1 的ObservedObjectLink方案要求嵌套对象逐层拆解自定义组件每一层配上ObjectLink代码复杂度随嵌套深度线性增长。V2 的ObservedV2Trace将观测能力实现在类属性上当类属性被Trace标记时无论嵌套多少层均能观测到变化。核心优势包括无需逐层创建自定义组件直接深度观测属性级精准刷新仅通知使用了该属性的 UI 片段刷新代码量大幅减少可删除中间层自定义组件。解读V2 的核心改进在于将观测能力从“组件层级”下沉到“类属性层级”。V1 需要组件层级配合才能实现深度观测V2 则直接在数据模型层面解决。习题 7简答题题目简述Monitor与Computed的职责边界以及各自的使用注意事项。答案Computed是派生值只做纯计算根据源状态返回结果不写任何状态。Monitor是副作用处理器用于执行校验、日志或触发外部动作不要设计成 A 的 Monitor 改 B。Computed只依赖可观测字段Monitor写完整路径监听。对于简单计算不建议使用计算属性因为计算属性本身也有开销。Computed只做纯计算Monitor只做副作用两者不应互相依赖或形成循环。解读Computed和Monitor都能响应状态变化但语义不同。前者是派生值后者是副作用处理器。正确使用两者可以避免循环依赖和更新时序问题。七、本节知识点总结V1 观测局限State仅能观察对象第一层属性嵌套对象需要逐层使用ObjectLink配合自定义组件代码复杂度随嵌套深度线性增长。ObservedV2 Trace将观测能力实现在类属性层级ObservedV2标记类可观察Trace标记需要观测的属性。嵌套类的每一层都需要ObservedV2且字段加Trace。被装饰的类必须用new实例化才具有观测能力。V2 组件装饰器ComponentV2对应ComponentLocal对应State禁止外部初始化Param对应Prop单向输入Event配合Param实现双向同步Once控制只初始化同步一次。Monitor 与 ComputedMonitor监听状态变量变化可获取变化前后的数据异步合并触发。Computed计算属性只依赖可观测字段避免重复计算。两者职责边界Computed做纯计算Monitor做副作用。迁移策略按“组件装饰器 → 数据模型 ObservedV2 化 → 存储方案”的顺序迁移。V1 组件中不能使用 V2 装饰器。下节预告第2课将进入自定义布局与绘制进阶的学习涵盖onMeasureSize/onPlaceChildren自定义布局接口、Canvas 自定义绘制、XComponent 原生渲染以及自定义组件的性能优化。
返回列表