前言
在之前的文章中我们简单了解了ArkTS
提供了一系列状态相关的装饰器,例如@State
,@Prop
,@Link
,@Provide
和@Consume
等等。
本文我们继续记录各种状态器所能观察到的变化范围
@State
允许装饰的类型
@State
允许装饰的变量类型有string、number、boolean、object、class
和enum
类型,以及这些类型的数组
。
框架能够观察到的变化
并不是@State
状态变量的所有更改都会引起UI的刷新,只有可以被框架观察到的修改才会引起UI刷新。能被框架观察到的变化如下
boolean、string、number
类型
当@State装饰的变量类型为boolean、string、number
类型时,可以观察到赋值的变化
例如
//状态变量定义
@State count:number = 1;
//状态变量操作
this.count++; //可以观察到
class、object
类型
注意:当@State
装饰的变量类型为class
或者object
时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为class
或者 object
,则嵌套属性的变化是观察不到的。
例如
//类型定义
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
时,元素属性的变化,是观察不到的。
例如
//类型定义
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++;//修改数组元素的属性,不可以观察到
总结
对于class
、object
和数组类型,框架仅能观察到@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
类型时,所有赋值的变化都可以观察到。
@Link
允许装饰的类型(同@State
)
@Link
允许装饰的变量类型有string、number、boolean、object、class
和enum
类型,以及这些类型的数组
。
框架能够观察到的变化(同@State
)
● 当装饰的数据类型为boolean、string、number
类型时,可以观察到数值的变化。
● 当装饰的数据类型为class
或者object
时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为 class
或者 object
,则嵌套属性的变化是观察不到的。
● 当装饰的数据类型为数组
时,可以可以观察到数组本身赋值的变化,和其元素的添加、删除及更新的变化,若元素类型为 class
或者object
时,元素属性的变化,是观察不到的。
@Provide
和 @Consume
允许装饰的类型(同@State
)
@Provide
和@Consume
允许装饰的变量类型有string、number、boolean、object、class
和enum
类型,以及这些类型的数组。
框架能够观察到的变化(同@State
)
● 当装饰的数据类型为boolean、string、number
类型时,可以观察到数值的变化
● 当装饰的数据类型为class
或者object
时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为 class
或者 object
,则嵌套属性的变化是观察不到的。
● 当装饰的数据类型为数组时,可以可以观察到数组本身赋值的变化,和其元素的添加、删除及更新的变化,若元素类型为 class
或者 object
时,元素属性的变化,是观察不到的。
总结
前文所述的装饰器都仅能观察到状态变量第一层的变化,而第二层的变化是观察不到的。如需观察到这些状态变量第二层的变化,则需要用到 ·@ObjectLink·和·@Observed·装饰器。
@ObjectLink
和 @Observed
示例代码
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
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;
}
}