【鸿蒙HarmonyOS开发笔记】深入状态管理,详解@ObjectLink 和 @Observed装饰器

前言

前篇回顾:【鸿蒙HarmonyOS开发笔记】状态管理入门

在之前的文章中我们简单了解了ArkTS 提供了一系列状态相关的装饰器,例如@State@Prop@Link@Provide@Consume等等。

本文我们继续记录各种状态器所能观察到的变化范围


@State

允许装饰的类型

@State允许装饰的变量类型有string、number、boolean、object、classenum类型,以及这些类型的数组

框架能够观察到的变化

并不是@State状态变量的所有更改都会引起UI的刷新,只有可以被框架观察到的修改才会引起UI刷新。能被框架观察到的变化如下

boolean、string、number类型

当@State装饰的变量类型为boolean、string、number类型时,可以观察到赋值的变化

例如

typescript 复制代码
//状态变量定义
@State count:number = 1; 

//状态变量操作
this.count++; //可以观察到

class、object类型

注意:当@State装饰的变量类型为class或者object时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为class或者 object,则嵌套属性的变化是观察不到的。

例如

typescript 复制代码
//类型定义
class Employee {
    name: string;
    age: number;
    job: Job;

    constructor(name: string, age: number, job: Job) {
        this.name = name;
        this.age = age;
        this.job = job;
    }
}

class Job {
    name: string;
    salary: number;

    constructor(name: string, salary: number) {
        this.name = name;
        this.salary = salary;
    }
}

//状态定义
@State employee: Employee = new Employee('张三', 28, new Job('销售', 8000))

//状态操作
employee = new Employee('李四', 26, new Job('行政', 6000))//状态变量重新赋值,可以观察到

employee.age++;//修改状态变量的属性,可以观察到

employee.job.salary++;//修改状态变量的属性的属性,不可以观察到

数组类型

@State装饰的变量类型为数组时,可以观察到数组本身赋值的变化,和其元素的添加、删除及更新的变化,若元素类型为 class 或者 object 时,元素属性的变化,是观察不到的。

例如

typescript 复制代码
//类型定义
export class Person {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
}



//状态定义
@State persons: Person[] = [new Person('张三', 19), new Person('李四', 20)];

//状态操作
persons = [];//状态变量重新赋值,可以观察到

persons.push(new Person('王五',21));//新增数组元素,可以观察到

persons[0]=new Person('张三',22);//对数组元素重新赋值,可以观察到

persons[1].age++;//修改数组元素的属性,不可以观察到

总结

对于classobject和数组类型,框架仅能观察到@State变量第一层属性的变化,例如employee.age++persons[0]=new Person('张三',22),但第二层属性的变化是观察不到的,例如employee.job.salary++persons[1].age++


@Prop

允许装饰的类型

@Prop允许装饰的变量类型有string、number、boolean、enum,注意不支持class、object数组

框架能够观察到的变化

当装饰的类型是允许的类型,即string、number、boolean、enum类型时,所有赋值的变化都可以观察到。


允许装饰的类型(同@State

@Link允许装饰的变量类型有string、number、boolean、object、classenum类型,以及这些类型的数组

框架能够观察到的变化(同@State

● 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。

● 当装饰的数据类型为class或者object时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为 class 或者 object,则嵌套属性的变化是观察不到的。

● 当装饰的数据类型为数组时,可以可以观察到数组本身赋值的变化,和其元素的添加、删除及更新的变化,若元素类型为 class 或者object时,元素属性的变化,是观察不到的。


@Provide @Consume

允许装饰的类型(同@State

@Provide@Consume允许装饰的变量类型有string、number、boolean、object、classenum类型,以及这些类型的数组。

框架能够观察到的变化(同@State

● 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化

● 当装饰的数据类型为class或者object时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为 class 或者 object,则嵌套属性的变化是观察不到的。

● 当装饰的数据类型为数组时,可以可以观察到数组本身赋值的变化,和其元素的添加、删除及更新的变化,若元素类型为 class 或者 object 时,元素属性的变化,是观察不到的。


总结

前文所述的装饰器都仅能观察到状态变量第一层的变化,而第二层的变化是观察不到的。如需观察到这些状态变量第二层的变化,则需要用到 ·@ObjectLink·和·@Observed·装饰器。


示例代码

typescript 复制代码
import { Employee, Job } from './model/DataModel'

@Entry
@Component
struct EmployeeInfo {
  @State employee: Employee = new Employee('张三', 28, new Job('销售', 8000))

  build() {
    Column() {
      Column({ space: 20 }) {
        Row({ space: 20 }) {
          Text('姓名').textStyle()
          Text(this.employee.name).textStyle()
        }

        Row({ space: 20 }) {
          Text('年龄').textStyle()
          Counter() {
            Text(this.employee.age.toString()).textStyle()
          }
          .onInc(() => {
            this.employee.age++;
          })
          .onDec(() => {
            this.employee.age--;
          })
        }

        Row({ space: 20 }) {
          Text('岗位').textStyle()
          JobInfo({ job: this.employee.job })
        }

      }
      .width('100%')
      .backgroundColor(Color.White)
      .borderRadius(10)
      .alignItems(HorizontalAlign.Start)
      .padding(20)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#E9E9EA')
    .padding(10)
    .justifyContent(FlexAlign.Center)
  }
}


@Component
struct JobInfo {
  @ObjectLink job: Job

  build() {
    Column({ space: 10 }) {
      Row({ space: 20 }) {
        Text('名称').textStyle()
        Text(this.job.name).textStyle()
      }

      Row({ space: 20 }) {
        Text('薪资').textStyle()
        Counter() {
          Text(this.job.salary.toString()).textStyle()
        }
        .width(140)
        .onInc(() => {
          this.job.salary++;
        })
        .onDec(() => {
          this.job.salary--;
        })
      }
    }
    .backgroundColor('#CCE3CB')
    .padding(20)
    .borderRadius(10)
    .alignItems(HorizontalAlign.Start)
  }
}


@Extend(Text) function textStyle() {
  .fontSize(20)
  .fontWeight(FontWeight.Medium)
}

DataModel

typescript 复制代码
export class Employee {
    name: string;
    age: number;
    job: Job;

    constructor(name: string, age: number, job: Job) {
        this.name = name;
        this.age = age;
        this.job = job;
    }
}

@Observed
export class Job {
    name: string;
    salary: number;

    constructor(name: string, salary: number) {
        this.name = name;
        this.salary = salary;
    }
}
相关推荐
xiaoyalian2 小时前
R语言绘图过程中遇到图例的图块中出现字符“a“的解决方法
笔记·r语言·数据可视化
Red Red3 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全
贰十六4 小时前
笔记:Centos Nginx Jdk Mysql OpenOffce KkFile Minio安装部署
笔记·nginx·centos
知兀4 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
醉陌离5 小时前
渗透测试笔记——shodan(4)
笔记
踏雪Vernon5 小时前
[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式
linux·docker·容器·harmonyos
LateBloomer7776 小时前
FreeRTOS——信号量
笔记·stm32·学习·freertos
legend_jz6 小时前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
Komorebi.py6 小时前
【Linux】-学习笔记04
linux·笔记·学习
fengbizhe7 小时前
笔试-笔记2
c++·笔记