ArkUI -- 状态管理 V1和 V2 混用
状态管理 V1 和 V2 混用时,由于观察机制不同,在变量传递和装饰器使用上存在严格限制。
- V1 侧重于组件层级的状态管理,如 V1 若要实现深度观察能力,需通过 @ObjectLink 逐层拆解嵌套类,并配合自定义组件使用
- V2 在增强了对数据对象的深度观察与管理能力,可灵活地控制数据与状态,实现更高效的 UI 刷新,提升应用性能。
状态管理V1和V2混用 (API19前)
状态管理V1和V2混用指导(API version 19前)
在 API19 之前,混用场景有相对严格的校验,状态管理 V1 与 V2 的混用规则入下
- V1 和 V2 的装饰器不可混用 (V1自定义组件不可使用 V2装饰器,V2自定义组件不可使用 V1装饰器,否则编译报错 )
- 若组件间不传递变量,则 V1自定义组件中可以使用 V2自定义组件,V2 自定义组件中可以使用 V1自定义组件
- 若组件间存在变量传递
- V1 向 V2 传递变量,有以下限制
- V1 中未被装饰器装饰的变量 (普通变量):V2 只能使用 @Param 接收
- V1 中被装饰器装饰的变量 (状态变量):V2 只能通过 @Param装 饰器接收,且仅限于 boolean、number、enum、string、undefined、null 这些简单类型数据
- V2 向 V1 传递变量,有以下限制
- V1 可以不使用装饰器接收数据,视为普通变量,观测不到变化
- V1 使用装饰器接收数据时,仅可通过 @State、@Prop、@Provide 接收数据,可以观测到变化,观测能力依赖 V1 装饰器;但不支持内置类型 (Array、Map、Set、Date) 数据,否则编译报错
- V1 的 @Link 只能被 V1 状态变量初始化;@ObjectLinke 只接收 @Observed 装饰的 class 初始化
- V1 接收 @ObservedV2 时,不能使用 V1 装饰器,但依赖 @ObservedV2+@Trace 的观测能力,其值的修改可触发 UI 刷新
- V1 向 V2 传递变量,有以下限制
V1 装饰器不可与 @ObservedV2 一起使用,V2 装饰器不可与 @ObservedV1 一起使用,否则编译报错
V1 向 V2 传递变量
- 传递未被装饰的变量时,V2 只能使用 @Param 接收
- 传递被装饰的状态变量时,V2 只能通过 @Param装 饰器接收,且仅限于 boolean、number、enum、string、undefined、null 这些简单类型数据,若传递了对象或内置类型 (Array、Map、Set、Date),会造成编译报错
- 传递对象时,通过监听 V1 组件内的 @Observed 对象,主动将修改同步给 @ObservedV2 对象实例,其不可用 V1 装饰器装饰
传递未被装饰的变量
当变量未被装饰器装饰时,不具备被观测的能力。
V2 组件对数据输入有严格的管理,将变量传递给 V2 时,必须通过 @Param 接收,观测能力为 @Param 能力。
对于接收的 Class,@Param 装饰只可观察到对象整体的变化,若要观测属性值的变化,需通过 @ObservedV2 和 @Trace 装饰,但由于其是从 V1 传递而来,不可能有 @ObservedV2 装饰
classInfo{age:number;name:string;constructor(age?:number,name?:string){this.age=age||20;this.name=name||'assassin';}}@ComponentV2struct ChildV2{// V2对数据输入有严格的管理,从父组件传入数据时,必须使用 @Param 装饰器进行数据接收@Param@Oncemessage:string="hello";// 可以观测到变化,并刷新 UI,@Once 使 @Param 装饰的变量可改变@Param@OnceundefinedVal:string|undefined=undefined;@Param@Onceinfo:Info=newInfo();// 非 @ObservedV2 对象,观测不到类属性的变化@Require@Param@Onceset:Set<number>;build(){Column({space:20}){Text('ChildV2')Button('message: '+this.message).onClick(()=>{// 触发 UI 刷新this.message+="_V2";})Button('undefinedVal: '+this.undefinedVal).onClick(()=>{// 触发 UI 刷新this.undefinedVal+="change to define";})Button(`info: {name:${this.info.name}, age:${this.info.age}`).onClick(()=>{// 不刷新 UIthis.info.age++;})Button(`new info: {name:${this.info.name}, age:${this.info.age}`).onClick(()=>{// 触发 UI 刷新this.info=newInfo(0,'V2');})ForEach(Array.from(this.set.values()),(item:number)=>{// 显示set变量Text(`${item}`)})}.width('100%').padding(20).backgroundColor(Color.Orange)}}@Entry@Componentexportstruct CompV1{message:string='Hello World';// 简单数据undefinedVal:undefined=undefined;// undefinedinfo:Info=newInfo();// 普通对象set:Set<number>=newSet([10,20]);// 内置类型 Setbuild(){Column({space:20}){Button('message: '+this.message).onClick(()=>{// message 没有装饰器,值的改变不会触发 UI 刷新this.message+='_v1'})ChildV2({message:this.message,undefinedVal:this.undefinedVal,info:this.info,set:this.set})}.width('100%')}}传递简单类型状态变量
V1 向 V2 传递变量时,仅支持传递简单类型数据 (boolean、number、string、null、undefined),且 V2 组件需使用 @Param 接收参数。
若传递了 V1装饰器 (如:@State) 装饰的对象或内置类型 (Array、Map、Set、Date),会造成编译报错。
将上述示例中的 CompV1 组件中的变量,添加装饰器
@Entry@Componentexportstruct CompV1{@Statemessage:string='Hello World';// 简单数据,支持传递@StateundefinedVal:undefined=undefined;// undefined,简单数据,支持传递@Stateinfo:Info=newInfo();// 对象,不支持传递,编译报错@Stateset:Set<number>=newSet([10,20