Để tăng cường khả năng quan sát thay đổi thuộc tính của đối tượng lớp trong khung quản lý trạng thái, các nhà phát triển có thể sử dụng hai trang trí (decorator) là @ObservedV2 và @Trace để áp dụng cho lớp cũng như các thuộc tính bên trong.
@ObservedV2 và @Trace cung cấp khả năng theo dõi trực tiếp sự thay đổi của các thuộc tính đối tượng lồng nhau, đây là một trong những tính năng cốt lõi của phiên bản quản lý trạng thái V2. Trước khi đọc tài liệu này, bạn nên tham khảo phần "[Tổng quan về quản lý trạng thái]" để hiểu rõ hơn về kiến trúc tổng thể của phiên bản V2.
Chú thích:
- @ObservedV2 và @Trace bắt đầu được hỗ trợ từ phiên bản API 12 trở lên.
Tổng quan
Cả hai decorator @ObservedV2 và @Trace đều cần thiết để làm việc cùng nhau:
- Chỉ khi cả hai được sử dụng đồng thời thì chúng mới có hiệu lực.
- Khi một thuộc tính được trang trí bởi @Trace thay đổi giá trị, chỉ các thành phần giao diện liên quan đến thuộc tính đó mới được làm mới.
- Trong trường hợp lớp lồng nhau, chỉ khi lớp con được trang trí bởi @ObservedV2 và thuộc tính của nó được trang trí bởi @Trace thì UI mới được cập nhật.
- Các thuộc tính không được trang trí bởi @Trace sẽ không kích hoạt làm mới giao diện khi thay đổi.
Giới hạn của phiên bản Quản lý trạng thái V1
Phiên bản V1 không thể trực tiếp theo dõi sự thay đổi của các thuộc tính đối tượng lồng nhau. Dưới đây là ví dụ minh họa:
@Observed
class Cha {
con: Con;
constructor(ten: string, tuoi: number) {
this.con = new Con(ten, tuoi);
}
}
@Observed
class Con {
ten: string;
tuoi: number;
constructor(ten: string, tuoi: number) {
this.ten = ten;
this.tuoi = tuoi;
}
}
@Entry
@Component
struct Index {
@State cha: Cha = new Cha("John", 8);
build() {
Row() {
Column() {
Text(`Ten: ${this.cha.con.ten} Tuoi: ${this.cha.con.tuoi}`)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
this.cha.con.tuoi++;
})
}
.width('100%')
}
.height('100%')
}
}
Trong đoạn mã trên, khi nhấn vào thành phần Text để tăng tuổi của con, giao diện sẽ không được làm mới vì V1 không thể nhận ra sự thay đổi của thuộc tính tuoi.
Sử dụng @ObservedV2 và @Trace
Decorator @ObservedV2 áp dụng cho lớp, còn @Trace áp dụng cho các thuộc tính bên trong lớp. Dưới đây là cách chúng hoạt động:
Quan sát thay đổi thuộc tính
@ObservedV2
class Con {
@Trace tuoi: number = 100;
}
class Cha {
con: Con = new Con();
}
@Entry
@ComponentV2
struct Index {
cha: Cha = new Cha();
build() {
Column() {
// Khi nhấp chuột thay đổi 'tuoi', thành phần Text sẽ được làm mới
Text(`${this.cha.con.tuoi}`)
.onClick(() => {
this.cha.con.tuoi++;
})
}
}
}
Trường hợp kế thừa
@ObservedV2
class Cha {
@Trace ten: string = "Tom";
}
class Con extends Cha {}
@Entry
@ComponentV2
struct Index {
con: Con = new Con();
build() {
Column() {
// Thay đổi tên sẽ làm mới giao diện
Text(`${this.con.ten}`)
.onClick(() => {
this.con.ten = "Jack";
})
}
}
}
Thuộc tính tĩnh
@ObservedV2
class QuanLy {
@Trace static soLuong: number = 1;
}
@Entry
@ComponentV2
struct Index {
build() {
Column() {
// Thay đổi giá trị 'soLuong' sẽ làm mới giao diện
Text(`${QuanLy.soLuong}`)
.onClick(() => {
QuanLy.soLuong++;
})
}
}
}
Hạn chế sử dụng
- Các thuộc tính không được trang trí bởi @Trace sẽ không kích hoạt làm mới giao diện.
- @ObservedV2 chỉ có thể áp dụng cho lớp, không phải cho thành phần tùy chỉnh.
- Không thể sử dụng @Trace trên lớp không được trang trí bởi @ObservedV2.
- Không hỗn hợp @ObservedV2/@Trace với các decorator khác như @Observed hoặc @Track.
- Không hỗ trợ sử dụng JSON.stringify trên các đối tượng được trang trí bởi @ObservedV2.
Trường hợp sử dụng
Lớp lồng nhau
@ObservedV2
class But {
@Trace doDai: number = 21;
}
class Tui {
rong: number = 50;
cao: number = 60;
but: But = new But();
}
class Tre {
tuoi: number = 5;
truong: string = "Mot truong nao do";
tui: Tui = new Tui();
}
@Entry
@ComponentV2
struct Trang {
tre: Tre = new Tre();
lanRender: number = 0;
render(id: number): number {
console.info(`id: ${id} lanRender: ${this.lanRender}`);
this.lanRender++;
return 40;
}
build() {
Column() {
Text('Do dai but ' + this.tre.tui.but.doDai)
.fontSize(this.render(1))
Button("Thay doi do dai")
.onClick(() => {
this.tre.tui.but.doDai += 100;
})
Button("Gan lai Tre")
.onClick(() => {
this.tre = new Tre();
})
}
}
}
Mảng cơ bản
let idKeTiep: number = 0;
@ObservedV2
class MangSo {
id: number = 0;
@Trace mangSo: number[] = [];
constructor() {
this.id = idKeTiep++;
this.mangSo = [0, 1, 2];
}
}
@Entry
@ComponentV2
struct TrangMang {
mang: MangSo = new MangSo();
build() {
Column() {
Button('Them phan tu')
.onClick(() => {
this.mang.mangSo.push(50);
})
Button('Xoa cuoi')
.onClick(() => {
this.mang.mangSo.pop();
})
ForEach(this.mang.mangSo, (phanTu: number, chiSo: number) => {
Text(`${chiSo} ${phanTu}`)
.fontSize(40)
})
}
}
}