HarmonyOS应用开发高级认证知识点梳理 (三)状态管理V2装饰器核心规则
以下是针对HarmonyOS应用开发高级认证备考的状态管理V2装饰器核心规则知识点系统梳理:
一、核心装饰器分类与功能
1. 组件声明装饰器
@ComponentV2
(1)基础定义与限制
功能定位
用于装饰自定义组件,启用V2状态管理能力,需配合V2专属装饰器(如@Local、@Param)使用
API支持:从API version 12开始支持
强制限制
不可与@Component混用,同一struct只能选择一种装饰器
内部禁止使用V1装饰器(如@State、@Link)
(2)核心特性
状态管理协同
仅支持V2装饰器家族:
@Local(组件内部状态,禁止外部初始化)
@Param(父子组件单向同步输入)
@Once(需与@Param联用,仅初始化同步一次)
性能优化参数
freezeWhenInactive:可选布尔参数,启用组件冻结功能以减少内存占用
(3)开发规范与认证考点
典型结构示例
@ComponentV2
struct MyComponent { @Local count: number = 0; // 内部状态@Param @Once title: string = "V2"; // 外部单次输入 build() { /* UI构建 */ }
}
高频错误排查
编译报错:尝试在@ComponentV2中使用@State等V1装饰器
状态失效:@Local变量被外部初始化(违反设计原则)
认证重点
装饰器选型对比:@ComponentV2与@Component的适用场景差异
状态管理机制差异
状态变量支持
@ComponentV2
仅支持V2状态装饰器:
@Local:替代@State,禁止外部初始化(纯内部状态)
@Param:父子组件单向同步(外部输入)
@Once:需与@Param联用,仅允许初始化同步一次
@Component
支持V1状态装饰器:
@State/@Prop/@Link等传统方案
@Observed+@ObjectLink实现嵌套监听(需逐层绑定)
嵌套对象监听能力
@ComponentV2:通过@ObservedV2+@Trace实现属性级精准更新,支持深层嵌套监听
@Component:依赖@Observed+@ObjectLink,仅支持第一层属性监听,深层需手动逐级传递
性能优化能力
特性 | @ComponentV2 | @Component |
---|---|---|
组件冻结 | 支持freezeWhenInactive 参数减少内存占用 | 不支持 |
复用机制 | 需配合@ReusableV2 实现实例缓存 | 原生支持组件复用 |
列表渲染效率 | 搭配@Trace 实现数组项级差分更新 | 数组更新常触发全量刷新 |
开发约束与兼容性
强制限制
@ComponentV2:
禁止使用V1装饰器(如@State、@Link)
暂不支持LocalStorage等全局状态管理
@Component:
禁止混用V2装饰器(如@Local)
迁移成本
@ComponentV2需重写状态逻辑,但深度监听场景代码量减少50%
@Component兼容旧项目,但嵌套数据结构维护复杂度更高
典型场景推荐
场景 | 推荐方案 | 核心优势 |
---|---|---|
深层嵌套对象监听 | @ComponentV2 | 属性级精准更新,避免全刷新 |
高频列表渲染 | @ComponentV2 +@ReusableV2 | 复用实例+项级更新提升帧率 |
简单父子组件通信 | @Component | @Prop /@Link 语法简洁 |
全局状态共享 | @Component | 原生支持AppStorage |
关键迁移提示:两者不可共存,同一组件只能选择一种装饰器方案。
状态同步机制:@Param与@Once的同步行为区别
1. @Param的同步行为
持续同步机制:当父组件的源数据变化时,@Param装饰的变量会自动同步更新,并触发子组件刷新。
例如:
@ComponentV2
struct Parent {@Local parentData: string = "Initial";build() {Column() {Child({ childParam: this.parentData }) // 父数据变化时,childParam同步更新}}
}
@ComponentV2
struct Child {@Param childParam: string; // 持续接收父数据变化
}
观测范围:支持简单类型(如number、string)和复杂类型(如Array、Object),对复杂类型的整体或元素变化均能观测。
限制:子组件内不允许直接修改@Param变量本身(仅能通过父组件源数据驱动更新)。
2. @Once的同步行为
一次性同步机制:仅在与@Param联用时生效,在子组件初始化时同步父组件数据一次,后续父数据变化不触发同步。
例如:
@ComponentV2
struct Child {@Param @Once childOnceParam: string; // 仅初始化时同步一次
}
使用场景:适用于数据初始化后需保持静态的场景(如配置参数),避免后续父数据变更干扰子组件状态。
强制约束:
必须与@Param搭配使用,单独使用无效。
禁止与其他装饰器(如@Local)混用。
3. 关键区别总结
特性 | @Param | @Once(需搭配@Param ) |
---|---|---|
同步时机 | 父数据实时同步(持续更新) | 仅初始化时同步一次(后续无更新) |
更新触发 | 父数据变化时自动刷新子组件 | 初始化后父数据变化不影响子组件 |
子组件内可修改性 | 禁止直接修改 | 允许在初始化后本地修改值 |
适用场景 | 需动态响应父数据变更(如实时列表) | 静态初始化数据(如一次性配置) |
典型错误示例:
错误:单独使用@Once(如@Once str: string)导致编译失败。
错误:在@Component(非V2)中混用@Once。
附:V1/V2装饰器对比表
特性 | V1 | V2 |
---|---|---|
状态变量装饰器 | @State /@Link | @Local /@Param |
组件复用 | 支持 | 暂不支持 |
对象深度监听 | 需多层@ObjectLink | @Trace 精准更新 |
@ReusableV2
(1)基础定义与版本适配
功能定位
用于标记@ComponentV2装饰的自定义组件可复用,通过缓存机制减少重复创建开销
API支持:需API version 12及以上,与V2状态管理系统深度绑定
核心优势
内存优化:复用组件实例及关联JSView对象,降低GC频率
性能提升:减少布局计算和渲染树diff时间(实测列表滑动性能提升95%+)
(2)关键机制与生命周期
复用流程
回收阶段:组件从树移除 → 触发aboutToRecycle() → 存入缓存池
复用阶段:匹配相同reuseId → 调用aboutToReuse(params) → 更新数据后插入新位置
生命周期对比
阶段 | 触发条件 | 典型操作 |
---|---|---|
aboutToRecycle | 组件被移入缓存池前 | 释放非共享资源(如定时器) |
aboutToReuse | 从缓存池复用时 | 重置状态/更新参数 |
(3)开发规范与认证考点
强制约束条件
必须与@ComponentV2联用,不可装饰@Builder函数或嵌套组件
组件需设计为无状态或状态可重置,否则复用会导致数据错乱
最佳实践示例
@ReusableV2
@ComponentV2
struct ListItem { @Param itemData: string; aboutToReuse(params: { itemData: string }) { this.itemData = params.itemData; // 必须显式更新参数 } build() { /* UI构建 */ }
}
高频错误排查
复用失效:未正确设置reuseId导致缓存池匹配失败
状态污染:未在aboutToReuse中清理前次状态
(4)认证核心考点
场景应用题
优化LazyForEach列表性能:通过@ReusableV2减少列表项创建销毁次数
条件渲染(if语句)下的复用策略
@ComponentV2
struct ItemView {@ReusableV2 // 启用实例复用build() {// 条件渲染逻辑(相同组件类型可复用)if (this.item.type === 'text') {Text(this.item.content).fontSize(16)} else {Text(this.item.content).fontSize(20)}}
}@Entry
@ComponentV2
struct MainPage {@Local listData: Array<{id: string, type: string, content: string}> = [...]build() {List() {LazyForEach(this.listData, (item: {id: string}) => {ListItem() {ItemView({ item: item }) // 复用ItemView实例}}, (item) => item.id) // 必须提供唯一key}}
}
@ComponentV2
struct ImageItem { ... } // 独立组件保证类型纯净@ComponentV2
struct TextItem { ... } // 独立组件保证类型纯净@ReusableV2
@ComponentV2
struct DynamicItem {build() {// 根据类型路由到不同组件(各自维护实例池)if (this.item.type === 'image') {ImageItem({ item: this.item })} else {TextItem({ item: this.item })}}
}
原理辨析题
V1与V2复用机制差异:V2需显式声明reuseId且依赖@ComponentV2
与@Local/@Param的状态协同规则
复用机制差异
基础依赖
V1复用:
原生支持组件复用,无需额外装饰器,但复用粒度较粗(基于组件类型)。
V2复用:
必须显式声明@ReusableV2并配合@ComponentV2使用,需通过reuseId精确控制实例池(如reuseId: () => 'customId')。
生命周期控制
V2新增aboutToReuse(复用前回调)和aboutToRecycle(回收前回调),支持状态重置。
V1复用无生命周期钩子,依赖组件自身aboutToAppear/aboutToDisappear。
性能优化
维度 | V1 | V2(@ReusableV2 ) |
---|---|---|
实例缓存 | 自动按类型缓存 | 需手动指定reuseId 分组缓存 |
内存占用 | 较高(无法冻结未活跃实例) | 支持freezeWhenInactive 冻结 |
列表渲染 | 全量刷新 | 项级差分更新 |
状态协同规则
@Local与@Param的协作
@Local:
仅限组件内部使用,禁止外部初始化(类似V1的@State但更严格)。
支持嵌套对象监听(需配合@Trace实现属性级更新)。
@Param:
父子组件单向同步,子组件禁止直接修改(除非搭配@Once)。
与@Local隔离:两者不可混用,@Param数据源必须来自父组件。
特殊场景处理
@Once联用:
@Param @Once组合使子组件仅初始化时同步父数据一次,后续可本地修改(类似@Local但保留初始值来源)。
典型应用:静态配置参数传递。
类型限制:
V2状态变量禁止与V1装饰器(如@State)混用,否则编译报错。
迁移建议
复用场景:高频列表渲染优先使用V2(@ReusableV2 + LazyForEach),简单组件复用可选V1。
状态协同:深层嵌套数据监听必须迁移至V2(@ObservedV2 + @Trace),简单父子通信可保留V1。
附:性能对比数据
指标 | 无复用方案 | @ReusableV2方案 |
---|---|---|
内存占用(千列表项) | 120MB | 35MB (-70%) |
滑动帧率 | 38fps | 60fps (+58%) |
2. 状态观测装饰器
@ObservedV2
(1)基础定义与版本要求
功能定位
用于装饰类,赋予类深度观测能力,需与@Trace配合实现嵌套对象属性级监听
API支持:从API version 12开始支持,属于状态管理V2的核心能力之一
核心特性
解决V1版本中@Observed+@ObjectLink的嵌套监听缺陷,支持直接观测深层属性无需逐层声明
实现精准更新:仅刷新关联属性的组件,避免整体对象刷新
(2)关键规则与约束
强制配合使用
必须与@Trace联用,单独使用无效
仅在@ComponentV2装饰的组件中生效,与V1装饰器(如@State)不兼容
观测范围限制
嵌套类:嵌套类需被@ObservedV2装饰且属性需@Trace标记才能触发UI更新
继承类:父类/子类属性需同时满足@ObservedV2+@Trace才可观测
数据类型支持
支持number/string/class/Array/Map/Set等类型,但不支持JSON序列化
(3)认证高频考点
场景应用题
电商商品价格更新:通过@ObservedV2+@Trace监听嵌套类Product.price变化
性能优化对比:V2版本比V1减少50%冗余代码(深度监听场景)
@ObservedV2
class Product {@Trace name: string = '';@Trace price: number = 0;
}@ObservedV2
class ShopCart {@Trace items: Product[] = [new Product()];
}@Entry
@ComponentV2
struct Index {@Local cart: ShopCart = new ShopCart();build() {Column() {Button('涨价').onClick(() => {this.cart.items[0].price += 10; // 触发精准更新})ProductView({ cart: this.cart })}}
}@ComponentV2
struct ProductView {@Param cart: ShopCart;build() {Text(`当前价格:${this.cart.items[0].price}`)}
}
错误排查题
UI不更新:检查嵌套属性是否遗漏@Trace或类未加@ObservedV2
编译报错:在@Component中混用@ObservedV2
原理辨析题
与V1的@Observed区别:V2支持属性级更新,V1需@ObjectLink逐层绑定
与@Local/@Param的协同规则:@ObservedV2类实例可作为二者的数据类型
@ObservedV2与V1的@Observed核心区别
监听粒度
V1:
仅能观测类实例的第一层属性变化,嵌套属性需通过@ObjectLink逐层绑定自定义组件实现监听
示例:修改obj.a.b.c需为b和c分别创建@ObjectLink绑定链
V2:
通过@Trace实现属性级精准监听,嵌套属性(如obj.a.b.c)可直接触发UI更新
无需中间组件传递,代码量减少50%以上
性能优化
维度 | V1(@Observed+@ObjectLink ) | V2(@ObservedV2+@Trace ) |
---|---|---|
更新范围 | 全对象刷新(即使仅修改深层属性) | 仅更新关联属性绑定的组件 |
内存占用 | 需缓存完整对象树 | 支持freezeWhenInactive 冻结未活跃实例 |
代码复杂度 | 高(需手动维护绑定链) | 低(直接访问嵌套属性) |
典型场景对比
// V1实现嵌套监听(需链式绑定)
@Observed class A { b: B = new B(); }
@Observed class B { c: number = 0; }
@Component struct Child {@ObjectLink b: B; // 需中间组件传递build() { Text(`${this.b.c}`) }
}
// V2实现同等功能
@ObservedV2 class A { @Trace b: B = new B(); // 直接监听嵌套类
}
@ObservedV2 class B { @Trace c: number = 0; // 属性级监听
}
@ComponentV2 struct Child {@Param a: A;build() { Text(`${this.a.b.c}`) } // 直接访问深层属性
}
与@Local/@Param的协同规则
数据类型兼容性
@ObservedV2类实例可作为@Local或@Param的数据类型,但需遵守:
@Local:禁止从外部初始化,仅限组件内部使用
@Param:必须由父组件传入,子组件不可直接修改(除非配合@Once)
状态同步机制
@Local + @ObservedV2:
组件内修改@Trace属性自动触发UI更新
示例:
@ComponentV2 struct Demo {@Local product: Product = new Product(); // @ObservedV2类实例build() {Button(`价格:${this.product.price}`).onClick(() => { this.product.price += 10; }) // 直接修改生效}
}
@Param + @ObservedV2:
父组件修改数据会同步到子组件,但子组件需通过@Event回调通知父组件修改
示例:
@Entry @ComponentV2 struct Parent {@Local cart: ShopCart = new ShopCart(); // @ObservedV2类build() {Child({ cart: this.cart, onPriceChange: (v) => { this.cart.price = v; } })}
}@ComponentV2 struct Child {@Param cart: ShopCart;@Event onPriceChange: (v: number) => void;build() {Button(`修改价格`).onClick(() => { this.onPriceChange(99); })}
}
静态属性支持
@ObservedV2类的静态属性若被@Trace装饰,同样支持状态管理:
@ObservedV2 class Config {@Trace static discount: number = 0.8; // 全局状态
}
迁移建议
优先使用V2的场景:
深层嵌套对象监听(如电商商品SKU树)
高频数据更新(如实时价格刷新)
保留V1的场景:
简单父子组件通信(无需嵌套监听)
兼容旧版代码库时
附:V1/V2性能对比
场景 | V1方案 | V2方案 |
---|---|---|
嵌套对象监听 | 需多层@ObjectLink | 单层@Trace 直达 |
数组更新效率 | 全量刷新 | 项级差分更新 |
@Trace
(1)基础特性
作用机制
必须与@ObservedV2配合使用,单独使用无效
仅能修饰类属性(如number/string/class/Array等),不能用于struct
属性变化时触发精准UI更新(仅刷新关联组件)
深度观测能力
支持嵌套类属性监听(需逐层标记@ObservedV2和@Trace)
@ObservedV2 class A { @Trace b: B = new B(); // 嵌套类属性
}
@ObservedV2 class B { @Trace value: number = 0; // 深层属性
}
(2)使用限制
作用域规则
仅能在@ComponentV2组件中使用
禁止与V1装饰器(如@State、@ObjectLink)混用
特殊场景
静态属性:支持@Trace static全局状态管理
继承类:父类/子类属性需分别标记@Trace
未标记属性:修改时不会触发UI刷新
(3)性能优化
对比V1方案
维度 | V1(@ObjectLink ) | V2(@Trace ) |
---|---|---|
代码量 | 需手动维护绑定链(冗余50%+) | 直接访问嵌套属性 |
更新范围 | 全对象刷新 | 属性级差分更新 |
内存占用 | 缓存完整对象树 | 冻结未活跃实例(freezeWhenInactive ) |
3. 数据流控制装饰器
@Local
(1)基础特性
作用定位
专用于@ComponentV2组件内部状态管理,对标V1的@State但语义更严格
被装饰的变量禁止从外部初始化,必须组件内初始化
变量变化时自动触发关联UI刷新
观测能力
支持基本类型(number/string/boolean)和复杂类型(Object/Array/Map等)
对复杂类型:
对象整体赋值可观测
数组元素变化可观测(通过API调用)
(2)与V1的@State核心区别
维度 | V1 @State | V2 @Local |
---|---|---|
数据来源 | 允许外部初始化(父组件传入) | 仅限内部初始化 |
语义明确性 | 状态来源混杂难维护 | 强制内部状态隔离 |
兼容性 | 支持V1组件 | 仅限@ComponentV2 组件 |
(3)使用规范与限制
强制规则
必须与@ComponentV2配合使用,在V1组件中无效
禁止与@Observed(V1)混用,需改用@ObservedV2
初始化要求
@ComponentV2
struct MyComponent {@Local count: number = 0; // 合法(内部初始化)// @Local msg: string; // 非法(未初始化)
}
(4)高级应用场景
与@Param协作
@Local用于组件内部状态,@Param用于父组件传参
典型模式:父组件通过@Param传参,子组件用@Local维护衍生状态
性能优化
相比V1减少冗余状态监听,精准触发UI更新
支持freezeWhenInactive冻结非活跃实例内存
@Param
(1)基础特性
作用定位
专用于@ComponentV2组件接收父组件传入的状态数据,实现单向数据流
被装饰变量禁止组件内部直接修改,需通过@Event回调通知父组件修改
数据同步机制
父组件数据源变化时自动同步到子组件的@Param变量
对复杂类型(如类对象),子组件可修改其属性并同步回父组件
(2)与V1装饰器对比
维度 | V1 @Prop | V2 @Param |
---|---|---|
数据方向 | 严格单向(父→子) | 单向但支持属性级修改 |
类型支持 | 基础类型+简单对象 | 全类型(含Map/Set等) |
初始化 | 必须父组件传入 | 支持本地初始化(非必须) |
(3)核心规则
强制约束
必须与@ComponentV2组件配合使用,V1组件中无效
变量类型需与父组件数据源严格一致
观测能力
基本类型:整体赋值可观测
对象类型:仅观测对象引用变化(属性修改需配合@ObservedV2)
数组/Map:API调用引发的变化可观测(如push/set)
(4)高级用法
联合@Once
@Param @Once变量仅初始化时同步一次,后续父组件变化不更新子组件
@ComponentV2 struct Child {@Param @Once initValue: string; // 仅首次同步
}
联合@Require
强制要求父组件传参,否则编译报错
@ComponentV2 struct Child {@Require @Param requiredData: string;
}
@Once
(1)基础特性
作用定位
专用于实现变量仅初始化时同步一次外部值,后续数据源变化不更新子组件
必须与@Param联合使用,不可单独使用或搭配其他装饰器
数据拦截机制
仅拦截数据源变化,不影响@Param的观测能力
允许子组件本地修改@Param变量的值(解除常规@Param不可修改限制)
(2)核心规则
维度 | 说明 |
---|---|
装饰顺序 | @Once @Param 或@Param @Once 均可,顺序无影响 |
使用范围 | 仅限@ComponentV2 组件,V1组件无效 |
类型支持 | 支持@Param 所有类型(基础类型/对象/数组等) |
(3)典型应用场景
初始化后隔离父组件更新
@ComponentV2 struct Child {@Param @Once fixedConfig: string; // 仅首次同步父组件配置
}
本地可修改的只读参数
@ComponentV2 struct Child {@Param @Once mutableValue: number; // 父组件初始化后可本地修改
}
(4)与相似装饰器对比
装饰器 | 数据同步机制 | 可修改性 | 典型场景 |
---|---|---|---|
@Param | 父→子持续同步 | 子组件不可修改 | 需响应父组件变化的参数 |
@Local | 完全内部状态 | 可自由修改 | 纯组件内部状态管理 |
@Once | 仅首次同步 | 初始化后可修改 | 需初始值但隔离更新的配置 |
二、高级特性与规则
1. 跨组件通信
@Provider与@Consumer
(1)基础特性
作用定位
实现跨组件层级的双向数据同步,无需逐层传递参数
@Provider为数据提供方,@Consumer为数据消费方,通过aliasName建立绑定关系
版本要求
仅支持@ComponentV2组件,V1组件使用会编译报错
从API version 12开始支持
(2)核心规则
维度 | @Provider | @Consumer |
---|---|---|
初始化 | 必须本地初始化 | 可本地初始化(未找到@Provider 时使用默认值) |
数据同步 | 数据变化自动同步到所有绑定的@Consumer | 自动同步最近的@Provider 数据 |
类型约束 | 需与@Consumer 类型严格一致 | 需与@Provider 类型严格一致 |
(3)关键机制
绑定规则
通过相同变量名或相同aliasName建立绑定
若未指定aliasName,默认使用属性名匹配
作用域
@Consumer向上查找最近父节点的@Provider
支持一对多绑定(一个@Provider可对应多个@Consumer)
复杂类型支持
支持对象/数组等复杂类型,需配合@ObservedV2实现属性级观测
@Event
(1)基础特性
作用定位
专用于实现父子组件事件回调,简化组件间通信逻辑
需与@ComponentV2配合使用,V1组件无效
核心能力
支持定义带参数的回调函数,参数类型需显式声明
通过事件触发父组件状态更新,实现数据反向传递
(2)核心规则
维度 | 说明 |
---|---|
装饰对象 | 仅能修饰回调函数(不能修饰变量) |
参数传递 | 支持多参数传递,需在声明时指定类型(如(count: number, text: string) => void ) |
绑定方式 | 父组件通过属性传递回调函数,子组件通过@Event 接收 |
命名规范 | 建议以on 前缀命名(如onCountChange ) |
(3)典型应用场景
子组件通知父组件
// 父组件
handleUpdate = (newVal: number) => { this.parentVal = newVal;
}
ChildComponent({ onUpdate: this.handleUpdate })// 子组件
@Event onUpdate: (val: number) => void;
Button('+1').onClick(() => this.onUpdate(100))
双向数据流实现(配合@Param)
// 父组件
@Local count: number = 0;
ChildComponent({ count: this.count, onCountChange: (v) => { this.count = v }
})// 子组件
@Param count: number;
@Event onCountChange: (v: number) => void;
(4)与相似装饰器对比
装饰器 | 数据流向 | 典型场景 |
---|---|---|
@Param | 父→子单向 | 父组件传递只读数据 |
@Link | 父子双向 | 需双向绑定的状态 |
@Event | 子→父单向 | 子组件触发父组件逻辑 |
2. 性能优化装饰器
@Computed
(1)基础特性
作用定位
用于定义计算属性,优化重复计算的性能开销
依赖的状态变量变化时自动触发重新计算,但仅计算一次
版本要求
仅支持@ComponentV2组件,V1组件无效
(2)核心规则
维度 | 说明 |
---|---|
装饰对象 | 只能修饰getter 方法,不能修饰普通属性或方法 |
计算时机 | 首次访问时计算,依赖项变化后再次访问时重新计算 |
数据流 | 单向只读,不可用于双向绑定 |
依赖限制 | 计算函数内不能修改其他状态变量 |
(3)典型应用场景
复杂计算逻辑封装
@Computed get fullName() {return `${this.firstName} ${this.lastName}`; // 合并姓名
}
性能敏感场景优化
@Computed get filteredList() {return this.rawList.filter(item => item.score > 60); // 避免重复过滤
}
(4)与相似装饰器对比
装饰器 | 数据特性 | 典型场景 |
---|---|---|
@Local | 可读写状态 | 组件内部状态管理 |
@Param | 父→子单向 | 父组件传递只读数据 |
@Computed | 只读计算值 | 依赖多项数据的派生状态 |
@Monitor
(1)基础特性
作用定位
增强状态变量变化的监听能力,支持深度监听嵌套对象/数组等复杂数据结构
对标V1的@Watch,但功能更强大,支持变化前后值对比
版本要求
仅支持@ComponentV2组件,API version 12起支持
(2)核心规则
维度 | 说明 |
---|---|
监听对象 | 需被@Local 、@Param 、@Provider 、@Consumer 或@Computed 修饰的变量 |
变化检测 | 使用严格相等(=== )比较,若不等则触发回调 |
回调时机 | 避免在回调中修改其他状态变量,可能引发循环更新 |
深度监听 | 需配合@ObservedV2 和@Trace 实现嵌套类/对象数组的属性级监听 |
(3)典型应用场景
基础监听
@Local @Monitor('onCountChange') count: number = 0;
onCountChange(newVal: number, oldVal: number) {console.log(`值从${oldVal}变为${newVal}`);
}
复杂类型监听
@ObservedV2 class NestedClass {@Trace value: string = '';
}
@Local @Monitor('onNestedChange') obj: NestedClass = new NestedClass();
(4)与@Watch对比
特性 | @Watch (V1) | @Monitor (V2) |
---|---|---|
监听范围 | 仅一级属性 | 支持深度嵌套属性 |
回调参数 | 无变化前后值 | 提供newVal/oldVal |
多属性监听 | 需单独声明 | 单装饰器可监听多属性 |
3. 关键约束规则
依赖关系:
@ObservedV2必须搭配@Trace使用,单独使用无效
@Once必须与@Param联用,否则无法生效
更新机制:
嵌套类中,需同时满足@ObservedV2装饰类和@Trace装饰属性才触发更新
修改Map/Set等内置类型需通过UIUtils.getTarget()获取原始对象
// 修改Map值示例
let rawMap = UIUtils.getTarget(this.stateMap);
rawMap.set('key', newValue); // 自动更新UI
三、认证高频考点
1. 装饰器选型场景
场景 | 推荐装饰器 |
---|---|
组件内部状态 | @Local (禁止外部初始化) |
父子组件数据同步 | @Param (外部输入)+ @Event (输出) |
深层嵌套对象监听 | @ObservedV2 + @Trace |
2. 典型错误排查
UI不更新:
检查嵌套属性是否遗漏@Trace装饰
确认类是否被@ObservedV2装饰
初始化报错:
@Local变量尝试从外部传入值
@Once未与@Param配合使用
3. 性能优化考点
避免在@Computed中执行耗时操作
优先使用@Trace替代@ObjectLink减少冗余渲染
附:V2 性能优势对比
场景 | V1 方案 | V2 方案 | 优化点 |
---|---|---|---|
嵌套对象监听 | 需多层@ObjectLink | @Trace 单层精准更新 | 减少 50% 冗余代码 |
数组更新 | 整体刷新 | 项级差分更新 | 降低渲染耗时 |