1)概念
在鸿蒙开发中会使用@State来装饰我们的变量,一旦变量发生变化,页面更新
遇到了复杂的数据结构,数据更新会有差别
比如嵌套对象,或者数组对象。
嵌套对象:如果修改的内层对象的属性,默认页面无法检测更新。
数组对象:修改数组页面都能检测变化,修改数组里面的对象属性,页面无法检测更新
(2)嵌套对象
代码演示效果
class Pat { id:string = '' name:string = '' type:string = '' constructor(id:string,name:string,type:string) { this.id = id this.name = name this.type = type } } class Student { id:string = '' name:string = '' pat:Pat constructor(id:string,name:string,pat:Pat) { this.id = id this.name = name this.pat = pat } } @Entry @Component struct ObjectLinkPage { @State message: string = 'Hello World'; //使用State修饰 @State stu1:Student = new Student('1','迪丽热巴',new Pat('1','大黄','金毛')) build() { Column() { Text(`${JSON.stringify(this.stu1)}`) .onClick(() =>{ // this.stu1.name = '小谷' //修改第一层数据,可以修改 // this.stu1.pat.name = '小黑' //修改stu1里的对象属性,发现没有反应无法修改 const pat1 = new Pat('2','小黑','拉布拉多') this.stu1.pat = pat1 //以这种方式整体修改,等于修改的第一层,可以修改 }) } .height('100%') .width('100%') } }
点击修改学生按钮:页面可以立即更新,修改学生信息可以在页面检测到
点击修改宠物按钮:页面不会更新,因为只能检测学生属性变化,无法深度监听内部对象变化
ArkTs为什么要这么做呢?
优势:如果做成这样,可以直接操作的话,性能消耗比较大
(3)对象数组
对象数组进行循环遍历的时候,如果直接操作数组中的元素,数组的变化能引起页面的更新,如果操作数组里面的对象属性,页面无法检测更新
@State school:Array<Student> = [ new Student('1','迪丽热巴',new Pat('1','大黄','金毛')), new Student('2','古力娜扎',new Pat('2','花花','泰迪')) ] ForEach(this.school,(item:Student,index:number) => { Text(`${JSON.stringify(item)}`) .fontSize(25) .fontColor(Color.Red) Button('点击修改学生名字') .onClick(() => { item.name = '默认名字'//发现点击之后没有效果,页面无法检测更新 }) }, (item:Student) => item.id) Button('数组里添加一个数据').onClick((event: ClickEvent) => { //页面可以检测更新 this.school.push(new Student('3','丫丫',new Pat('3','嘿嘿','二哈'))) })
(4)嵌套装饰器的使用
@ObjectLink和@Observed装饰器一般要一起使用,才能实现对象监听
@Observed放在类上面(model数据约束上面)
@ObjectLink放在组件中定义数据,无法在entry中使用
-
对数组的深度更新的解决方案
在Student.ets中
export class Pat { id:string = '' name:string = '' type:string = '' constructor(id:string,name:string,type:string) { this.id = id this.name = name this.type = type } } @Observed export class Student { id:string = '' name:string = '' pat:Pat constructor(id:string,name:string,pat:Pat) { this.id = id this.name = name this.pat = pat } }
在父组件中
@State school:Array<Student> = [ new Student('1','迪丽热巴',new Pat('1','大黄','金毛')), new Student('2','古力娜扎',new Pat('2','花花','泰迪')) ] ForEach(this.school,(item:Student,index:number) => { ObjectLinkList({item:item}) }, (item:Student) => item.id)
在子组件中
@Component export struct ObjectLinkList { @ObjectLink item:Student build() { Column() { Text(`${JSON.stringify(this.item)}`) .fontSize(25) .fontColor(Color.Red) Button('点击修改学生名字') .onClick(() => { this.item.name = '默认名字'//发现点击之后修改了 }) } .width('100%') .height('120') } }
子组件接收的数据就是你要监听的对象
@ObjectLink配合@Observed使用就能实现对指定的对象进行深度监听
-
对嵌套对象深度检测的解决方法
@State stu1:Student = new Student('1','迪丽热巴',new Pat('1','大黄','金毛')) ObjectLinkList2({pat:this.stu1.pat}) @ObjectLink pat:Pat // pat:Student = new Student('1','迪丽热巴',new Pat('1','大黄','金毛')) build() { Column(){ Text(`${JSON.stringify(this.pat)}`) .onClick(() =>{ this.pat.name = '小谷' //修改第一层数据,可以修改 }) Text(`${JSON.stringify(this.pat)}`) .onClick(() => { this.pat.name = '哈哈哈' }) } }
总结:如果页面上只是渲染嵌套对象,那我们无需进行干预,直接渲染出来就可以了但是如果要针对嵌套对象进行修改,一定要创建一个子组件,将这个对象传递给子组件专门进行页面渲染以及修改。也需要给model数据约束增加@Observed以及@ObjectLink来接收修改对象
(5)属性装饰器@ObservedV2装饰器和@Trace装饰器
为了解决@ObjectLink配合@Observed装饰器在使用时繁琐的步骤,推出了@ObservedV2装饰器和@Trace,可以对对象进行深度检测,
代码实例:
@ObservedV2 export class Pat2 { id:string = '' @Trace name:string = '' type:string = '' constructor(id:string,name:string,type:string) { this.id = id this.name = name this.type = type } } @ObservedV2 export class Student2 { id:string = '' @Trace name:string = '' pat:Pat2 constructor(id:string,name:string,pat:Pat2) { this.id = id this.name = name this.pat = pat } }
在类中使用@ObservedV2说明要监测的对象,@Trace说明要监测的属性,未被@Trace装饰的属性不会被监测到
stu1:Student2 = new Student2('1','迪丽热巴',new Pat2('1','大黄','金毛')) build() { Column() { Text(`${this.stu1.name}`) .onClick(()=>{ this.stu1.name = '古镇' console.log('点击了第一个') }) Text(`${this.stu1.pat.name}`) .onClick(()=>{ this.stu1.pat.name = '啦啦啦啦' console.log('点击了第二个') }) }
在使用时就可以对嵌套对象的属性进行检测
@ObservedV2装饰器和@Trace装饰器无法与@status混合使用
@ObservedV2仅能装饰class,无法装饰自定义组件