目录
- HarmonyOS Next 状态管理:Local 装饰器实践
- HarmonyOS Next 状态管理:Param 装饰器实践
- HarmonyOS Next 状态管理:Once 装饰器实践
- HarmonyOS Next 状态管理:Event 装饰器实践
- HarmonyOS Next 状态管理:!! 状态装饰器实践
- HarmonyOS Next 状态管理:@ObserverV2和@Trace 装饰器实践
- HarmonyOS Next 状态管理:Provider和Consumer 装饰器实践
- HarmonyOS Next 状态管理:Monitor 装饰器实践
一. @Monitor 修饰器概述
@Monitor
是鸿蒙开发中用于增强状态管理框架对状态变量变化监听能力的一个装饰器。它能够监听状态变量的变化,并提供比 @Watch
更强大的功能,包括深度监听嵌套对象、数组等复杂数据结构的变化,并能够获取变化前后的值。
核心特性:
- 使用场景:
@Monitor
装饰器需在@ComponentV2
装饰的自定义组件中使用。- 被监听的变量需被状态装饰器(如
@Local
、@Param
、@Provider
、@Consumer
、@Computed
)修饰,否则无法监听其变化。
- 独立使用:
@Monitor
装饰器支持在类中独立使用,但该类需被@ObserverV2
修饰。- 在组件中,
@Monitor
可与@ObserverV2
和@Trace
配合使用,通过回调方法监听类属性的变化。
- 变化检测机制:
- 判断修饰对象是否变化时,使用严格相等(
===
)进行比较。若结果为false
(即不相等),则触发@Monitor
的回调。 - 若在一次事件中多次改变同一属性,
@Monitor
会使用初始值和最终值进行比较。
- 多属性监听:
- 单个
@Monitor
装饰器可同时监听多个属性的变化。若这些属性在一次事件中共同变化,仅触发一次回调。
- 深度监听:
@Monitor
支持深度监听嵌套类、多维数组、对象数组中指定项的变化。- 对于嵌套类或对象数组中成员属性的监听,要求该类被
@ObserverV2
修饰,且该属性被@Trace
修饰。
- 继承场景:
- 在继承类中,父子类可分别对同一属性定义
@Monitor
监听。当属性变化时,父子类中的@Monitor
回调均会被调用。
- 回调函数:
- 与
@Watch
装饰器类似,开发者需自定义回调函数。区别在于,@Watch
将函数名作为参数,而@Monitor
直接装饰回调函数。
二. @Monitor与@Watch对比
特性 | @Watch | @Monitor |
---|---|---|
参数 | 回调方法名 | 监听状态变量名、属性名。 |
监听目标数 | 只能监听单个状态变量 | 能同时监听多个状态变量 |
监听能力 | 只能监听一层属性 | 支持深度监听嵌套属性 |
能否获取变化前的值 | 不能获取变化前的值 | 能获取变化前后的值 |
监听条件 | 监听对象需为状态变量 | 监听对象为状态变量或为@Trace装饰的类成员属性 |
使用限制 | 仅能在 @Component 装饰的自定义组件中使用 |
可在 @ComponentV2 装饰的自定义组件或 @ObservedV2 装饰的类中使用 |
三. @Monitor的简单使用
3.1 代码演示
typescript
import { promptAction } from '@kit.ArkUI'
@Entry
@ComponentV2
struct Index {
@Local msg: string = "孙膑"
@Monitor('msg')
onMsgChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
const toastMsg = `${path} before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`
console.log(`${path} before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`)
promptAction.showToast({
message: toastMsg,
alignment: Alignment.Center
})
})
}
build() {
Column({space: 20}) {
Text(`msg:${this.msg}`)
Button('change msg')
.onClick(() => {
this.msg = `${Date.now().toString()}`
})
}
.width('100%')
}
}
关键点:
@Monitor
修饰的是字符串类型,其值是对象的变量名。@Monitor
装饰的变量不支持动态修改,即不支持在运行时修改。
3.2 拆解代码
3.2.1 IMonitor 接口
IMonitor
是一个接口类型,用于在 @Monitor
的回调函数中获取状态变量变化的信息。它的定义如下:
typescript
interface IMonitor {
dirty: Array<string>; // 发生变化的属性名数组
value<T>(path?: string): IMonitorValue<T>; // 获取指定属性的变化信息
}
属性
dirty
:一个字符串数组,存储了发生变化的属性名。例如,如果监听了message
和name
,当message
发生变化时,dirty
数组会包含"message"
。
方法
value<T>(path?: string)
:获取指定属性(path
)的变化信息。如果不传递path
,则返回第一个发生变化的属性的信息。返回值是一个IMonitorValue<T>
对象,包含变化前后的值。
3.2.2 IMonitorValue 接口
IMonitorValue<T>
是一个泛型接口,用于存储属性变化的信息。它的定义如下:
csharp
interface IMonitorValue<T> {
before: T; // 变化前的值
now: T; // 变化后的值
path: string; // 监听的属性名
}
属性
before
:属性变化前的值。now
:属性变化后的值。path
:监听的属性名。
3.2.3 dirty 的作用
dirty
是一个数组,存储了所有发生变化的属性名。它的作用是:
- 当
@Monitor
监听多个属性时,dirty
可以帮助开发者快速知道哪些属性发生了变化。 - 通过遍历
dirty
数组,可以逐个处理发生变化的属性。
四、实践探索
4.1 @Monitor
监听基础类型
@Monitor
可以直接修饰基础类型(如 string
、number
、boolean
、enum
、null
、undefined
等),并在变量变化时更新关联的 UI 组件。
typescript
import { promptAction } from '@kit.ArkUI'
enum Gender {
Female,
Male
}
@Entry
@ComponentV2
struct Index {
msg: string = "非状态变量"
@Local name: string = "孙膑"
@Local age: number = 28
@Local isMaimed: boolean = true
@Local occupation: undefined | string = undefined
@Local consort: null | string = null
@Local gender: Gender = Gender.Male
@Monitor('msg')
onMsgChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
promptAction.showToast({
message: `msg changed, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`,
alignment: Alignment.Center
})
})
}
@Monitor('name')
onNameChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
promptAction.showToast({
message: `name changed, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`,
alignment: Alignment.Center
})
})
}
@Monitor('age', 'isMaimed', 'occupation', 'consort', 'gender')
onVariablesChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
const toastMsg = `${path} changed, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`
console.log(toastMsg);
promptAction.showToast({
message: toastMsg,
alignment: Alignment.Center
})
})
}
build() {
Column({ space: 10 }) {
Text(`msg:${this.msg}`)
Text(`name:${this.name}`)
Text(`age:${this.age}`)
Text(`isMaimed:${this.isMaimed}`)
Text(`occupation:${this.occupation}`)
Text(`consort:${this.consort}`)
Text(`gender:${this.gender}`)
Button('更新非状态变量:msg')
.onClick(() => {
this.msg = "非状态变量" + `${Math.round(Math.random() * 1000)}`
})
Button('更新变量:name')
.onClick(() => {
this.name = "小乔"+ `${Math.round(Math.random() * 1000)}`
})
Button('更新其他所有变量')
.onClick(() => {
this.age++
this.isMaimed = !this.isMaimed
this.occupation = "未知" + `${Math.round(Math.random() * 1000)}`
this.consort = "周瑜" + `${Math.round(Math.random() * 1000)}`
this.gender = (this.gender == Gender.Female) ? Gender.Male : Gender.Female
})
}
.height('100%')
.width('100%')
}
}
关键点:
- 非状态变量的更新不会触发
@Monitor
回调。 @Monitor
支持修饰string
、number
、boolean
、enum
、null
、undefined
等基础类型。
less
// 第一次点击
03-15 07:23:16.982 32643-32643 A03d00/JSAPP com.examp...lication I age changed, before:28, now:29
03-15 07:23:16.983 32643-32643 A03d00/JSAPP com.examp...lication I isMaimed changed, before:true, now:false
03-15 07:23:16.983 32643-32643 A03d00/JSAPP com.examp...lication I occupation changed, before:undefined, now:未知807
03-15 07:23:16.983 32643-32643 A03d00/JSAPP com.examp...lication I consort changed, before:null, now:周瑜424
03-15 07:23:16.983 32643-32643 A03d00/JSAPP com.examp...lication I gender changed, before:1, now:0
// 第二次点击
03-15 07:23:19.553 32643-32643 A03d00/JSAPP com.examp...lication I age changed, before:29, now:30
03-15 07:23:19.553 32643-32643 A03d00/JSAPP com.examp...lication I isMaimed changed, before:false, now:true
03-15 07:23:19.553 32643-32643 A03d00/JSAPP com.examp...lication I occupation changed, before:未知807, now:未知232
03-15 07:23:19.553 32643-32643 A03d00/JSAPP com.examp...lication I consort changed, before:周瑜424, now:周瑜178
03-15 07:23:19.553 32643-32643 A03d00/JSAPP com.examp...lication I gender changed, before:0, now:1
- 不支持的类型 :
@Monitor
不支持修饰any
和unknown
类型。 - 单个
@Monitor
可以监听单个变量(例如: @Monitor('name'))的变化,也支持监听多个变化的变化(例如:@Monitor('age', 'isMaimed', 'occupation', 'consort', 'gender')) - 单个
@Monitor
装饰器能够同时监听多个属性的变化,当这些属性在一次事件(例如:本次是点击事件)中共同变化时,只会触发一次@Monitor
的回调方法。
4.2 @Monitor
监听实例对象
实践一
typescript
import { promptAction } from '@kit.ArkUI'
import { JSON } from '@kit.ArkTS'
import json from '@ohos.util.json'
class UserInfo {
name: string
age: number
address: Address
constructor(name: string, age: number, country: string) {
this.name = name
this.age = age
this.address = new Address(country)
}
}
class Address {
country: string
constructor(country: string) {
this.country = country
}
}
@Entry
@ComponentV2
struct Index {
@Local userInfo: UserInfo = new UserInfo("孙膑", 29, "齐国")
@Monitor('userInfo')
onUserInfoChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
promptAction.showToast({
message: `${path}, before:${JSON.stringify(monitor.value(path)?.before!)},
now:${JSON.stringify(monitor.value(path)?.now!)}`,
alignment: Alignment.Center
})
})
}
build() {
Column({space: 20}) {
Row() {
Text(`name:${this.userInfo.name}`)
Text(`age:${this.userInfo.age}`)
Text(`country:${this.userInfo.address.country}`)
}
.justifyContent(FlexAlign.SpaceAround)
.width('100%')
Button('更新实例对象')
.onClick(() => {
const name = this.userInfo.name == "孙膑" ? "庞涓" : "孙膑"
const country = this.userInfo.address.country == "齐国" ? "魏国" : "齐国"
this.userInfo = new UserInfo(name, this.userInfo.age++, country)
})
Button('更新属性')
.onClick(() => {
const name = this.userInfo.name == "孙膑" ? "庞涓" : "孙膑"
this.userInfo.name = name
this.userInfo.age++
})
}
.width('100%')
}
}
@Monitor
装饰实例对象,支持对象的重新赋值。但无法监听实例的属性变化。想要监听属性的变化,需要结合@ObserverV2
和 @Trace
来使用。
实践二
typescript
import { promptAction } from '@kit.ArkUI'
import { JSON } from '@kit.ArkTS'
import json from '@ohos.util.json'
@ObservedV2
class UserInfo {
@Trace name: string
age: number
address: Address
constructor(name: string, age: number, country: string) {
this.name = name
this.age = age
this.address = new Address(country)
}
}
class Address {
country: string
constructor(country: string) {
this.country = country
}
}
@Entry
@ComponentV2
struct Index {
@Local userInfo: UserInfo = new UserInfo("孙膑", 29, "齐国")
@Local user2Info: UserInfo = new UserInfo("赵云", 25, "蜀国")
@Monitor('userInfo.name')
onUserNameChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
promptAction.showToast({
message: `${path}, before:${JSON.stringify(monitor.value(path)?.before!)},
now:${JSON.stringify(monitor.value(path)?.now!)}`,
alignment: Alignment.Center
})
})
}
build() {
Column({space: 20}) {
Row() {
Text(`name:${this.userInfo.name}`)
Text(`age:${this.userInfo.age}`)
Text(`country:${this.userInfo.address.country}`)
}
.justifyContent(FlexAlign.SpaceAround)
.width('100%')
Row() {
Text(`name:${this.user2Info.name}`)
Text(`age:${this.user2Info.age}`)
Text(`country:${this.user2Info.address.country}`)
}
.justifyContent(FlexAlign.SpaceAround)
.width('100%')
Button('更新实例对象')
.onClick(() => {
const name = this.userInfo.name == "孙膑" ? "庞涓" : "孙膑"
this.userInfo.name = name
})
Button('更新实例对象: user2')
.onClick(() => {
const u2Name = this.user2Info.name == "赵云" ? "周瑜" : "赵云"
this.user2Info.name = u2Name
})
}
.width('100%')
}
}
关键点:
@Monitor
结合@ObserverV2
和@Trace
可以监听到属性的变化。在@Monitor
修饰的对象写法是userInfo.name,其他属性以此类推。- 在组件中
@Monitor
监听的是指定实例对象的属性,不能监听所有创建的对象的指定属性。所以,这里的user2Info 对象变更name 属性后并没有触发@Monitor
的监听回调。有点类似iOS的KVO用法。
实践三
typescript
import { promptAction } from '@kit.ArkUI'
import { JSON } from '@kit.ArkTS'
import json from '@ohos.util.json'
@ObservedV2
class UserInfo {
@Trace name: string
age: number
address: Address
constructor(name: string, age: number, country: string) {
this.name = name
this.age = age
this.address = new Address(country)
}
@Monitor('name')
onAgeChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
console.log(`${path}, from:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`)
promptAction.showToast({
message: `In Class: ${path}, before:${JSON.stringify(monitor.value(path)?.before!)},
now:${JSON.stringify(monitor.value(path)?.now!)}`,
alignment: Alignment.Center
})
})
}
}
class Address {
country: string
constructor(country: string) {
this.country = country
}
}
@Entry
@ComponentV2
struct Index {
@Local userInfo: UserInfo = new UserInfo("孙膑", 29, "齐国")
@Local user2Info: UserInfo = new UserInfo("赵云", 25, "蜀国")
@Monitor('userInfo.age')
onUserNameChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
console.log(`${path}, from:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`)
promptAction.showToast({
message: `${path}, before:${JSON.stringify(monitor.value(path)?.before!)},
now:${JSON.stringify(monitor.value(path)?.now!)}`,
alignment: Alignment.Center
})
})
}
build() {
Column({space: 20}) {
Row() {
Text(`name:${this.userInfo.name}`)
Text(`age:${this.userInfo.age}`)
Text(`country:${this.userInfo.address.country}`)
}
.justifyContent(FlexAlign.SpaceAround)
.width('100%')
Row() {
Text(`name:${this.user2Info.name}`)
Text(`age:${this.user2Info.age}`)
Text(`country:${this.user2Info.address.country}`)
}
.justifyContent(FlexAlign.SpaceAround)
.width('100%')
Button('更新实例对象user1的name')
.onClick(() => {
const name = this.userInfo.name == "孙膑" ? "庞涓" : "孙膑"
this.userInfo.name = name
})
Button('更新实例对象user2的name')
.onClick(() => {
const u2Name = this.user2Info.name == "赵云" ? "周瑜" : "赵云"
this.user2Info.name = u2Name
})
Button('更新实例对象属性: age')
.onClick(() => {
this.userInfo.age = this.userInfo.age + 1
})
}
.width('100%')
}
}
关键点:
@Monitor
可以在使用@ObserverV2
装饰的类中使用,在属性被@Trace
装饰后,任意对象的改属性变化后,在类中都会收到监听回调。具有收拢归一的效果。- 在类被
@ObserverV2
装饰后,属性未被@Trace
装饰,即使变量值变换也会无法触发监听回调。
实践四
typescript
import { promptAction } from '@kit.ArkUI'
import { JSON } from '@kit.ArkTS'
import json from '@ohos.util.json'
@ObservedV2
class People {
@Trace name: string
constructor(name: string) {
this.name = name
}
@Monitor('name')
onNameChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
console.log(`In People ${path}, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`)
})
}
}
@ObservedV2
class Student extends People {
studentId: string
gpa: number
constructor(studentId: string, name: string, gpa: number) {
super(name)
this.studentId = studentId
this.gpa = gpa
}
@Monitor('name')
onNameChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
console.log(`In Student ${path}, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`)
})
}
}
@Entry
@ComponentV2
struct Index {
@Local stu1: Student = new Student("123", "李雷", 4.1)
@Local stu2: Student = new Student("231", "韩梅梅", 4.9)
build() {
Column({space: 20}) {
Row() {
Text(`name:${this.stu1.name}`)
Text(`gpa:${this.stu1.gpa}`)
}
.justifyContent(FlexAlign.SpaceAround)
.width('100%')
Row() {
Text(`name:${this.stu2.name}`)
Text(`gpa:${this.stu2.gpa}`)
}
.justifyContent(FlexAlign.SpaceAround)
.width('100%')
Button('更新姓名')
.onClick(() => {
this.stu1.name = (this.stu1.name == "李雷") ? "小明" : "李雷"
this.stu2.name = (this.stu2.name == "韩梅梅") ? "小红" : "韩梅梅"
})
}
.width('100%')
}
}
less
// 第一次点击
03-15 09:00:13.126 3494-3494 A03d00/JSAPP com.examp...lication I In People name, before:李雷, now:小明
03-15 09:00:13.127 3494-3494 A03d00/JSAPP com.examp...lication I In Student name, before:李雷, now:小明
03-15 09:00:13.127 3494-3494 A03d00/JSAPP com.examp...lication I In People name, before:韩梅梅, now:小红
03-15 09:00:13.127 3494-3494 A03d00/JSAPP com.examp...lication I In Student name, before:韩梅梅, now:小红
// 第二次点击
03-15 09:00:16.613 3494-3494 A03d00/JSAPP com.examp...lication I In People name, before:小明, now:李雷
03-15 09:00:16.613 3494-3494 A03d00/JSAPP com.examp...lication I In Student name, before:小明, now:李雷
03-15 09:00:16.613 3494-3494 A03d00/JSAPP com.examp...lication I In People name, before:小红, now:韩梅梅
03-15 09:00:16.613 3494-3494 A03d00/JSAPP com.examp...lication I In Student name, before:小红, now:韩梅梅
关键点:
@Monitor
可以在继承场景中监听同一个属性的变化。在属性改变后,会触发父类和子类的监听回调。
4.3 @Monitor
监听容器对象
实践一
less
@Entry
@ComponentV2
struct Index {
@Local names: string[] = ["孙膑", "赵云", "马超"]
@Monitor('names')
onNamesChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
promptAction.showToast({
message: `${path}, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`,
alignment: Alignment.Center
})
})
}
build() {
Column({space: 20}) {
ForEach(this.names, (name: string) => {
Text(`name:${name}`)
})
Button('更新元素')
.onClick(() => {
this.names[0] = `${Date.now().toString()}`
})
Button('更新数组')
.onClick(() => {
this.names = ["李雷", "韩梅梅", "林涛"]
})
}
.width('100%')
}
}
关键点:
@Monitor
装饰数组时:只修改元素不会触发监听回调;重新创建数组对象赋值后才会触发监听回调。
实践二
typescript
@ObservedV2
class UserInfo {
@Trace name: string
@Trace age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
@Entry
@ComponentV2
struct Index {
@Local users: UserInfo[] = [new UserInfo("孙膑", 29), new UserInfo("庞涓", 31)]
@Monitor('users')
onNamesChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
promptAction.showToast({
message: `${path}, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`,
alignment: Alignment.Center
})
})
}
build() {
Column({space: 20}) {
ForEach(this.users, (user: UserInfo) => {
Row() {
Text(`name:${user.name}`)
Text(`age:${user.age}`)
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
})
Button('更新元素')
.onClick(() => {
this.users[0] = new UserInfo("马超", 25)
})
Button('更新数组')
.onClick(() => {
this.users = [new UserInfo("韩梅梅", 14), new UserInfo("李雷", 15)]
})
}
.width('100%')
}
}
关键点:
@Monitor
装饰元素是实例对象的数组时:只修改元素不会触发监听回调;重新创建数组对象赋值后才会触发监听回调。
4.4 @Monitor
监听 @Provider
对象
在之前的章节中我们介绍过 @Provider
和 @Consumer
装饰器,他们的一大特点是可以使用别名。那么@Monitor
监听的是变量名还是别名呢?
typescript
@Entry
@ComponentV2
struct Index {
@Provider('xNames') names: string[] = ["孙膑", "赵云", "马超"]
@Monitor('names')
onNamesChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
promptAction.showToast({
message: `${path}, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`,
alignment: Alignment.Center
})
})
}
build() {
Column({space: 20}) {
ForEach(this.names, (name: string) => {
Text(`name: ${name}`)
})
Button('update array')
.onClick(() => {
if (this.names.length > 2) {
this.names = ["李雷", "韩梅梅"]
} else {
this.names = ["孙膑", "赵云", "马超"]
}
})
}
.width('100%')
}
}
@ComponentV2
struct ChildComponent {
@Consumer('xNames') cNames: string[] = []
build() {
Column({space: 10}) {
ForEach(this.cNames, (name: string) => {
Text(`cName: ${name}`)
})
}
.width('100%')
}
}
关键点:
@Monitor
监听@Provider
和@Consumer
装饰的变量时,监听的是变量名,非别名。
4.5 自定义组件中@Monitor
对变量监听的生效及失效时间
页面有页面的生命周期,子组件也有自己的生命周期。那么从哪个时机点可以监听变量,哪个时机点监听会被移除呢?
less
@ObservedV2
class UserInfo {
@Trace name: string
@Trace age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
@Entry
@ComponentV2
struct Index {
@Local showChildComponent: boolean = true
@Local userInfo: UserInfo = new UserInfo("孙膑", 27)
@Monitor('userInfo.name')
onNamesChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
console.log(`In Fathor monitor: ${path}, before:${JSON.stringify(monitor.value(path)?.before!)},
now:${JSON.stringify(monitor.value(path)?.now!)}`)
})
}
build() {
Column({space: 20}) {
if (this.showChildComponent) {
ChildComponent({cUserInfo: this.userInfo})
}
Button('change name')
.onClick(() => {
this.userInfo.name = `${Date.now().toString()}`
})
Button('show/hide child component')
.onClick(() => {
this.showChildComponent = !this.showChildComponent
})
}
.width('100%')
}
}
@ComponentV2
struct ChildComponent {
@Param cUserInfo: UserInfo = new UserInfo("xx", -1)
@Monitor('cUserInfo.name')
onNamesChange(monitor: IMonitor) {
monitor.dirty.forEach((path) => {
console.log(`In Child monitor:${path}, before:${monitor.value(path)?.before}, now:${monitor.value(path)?.now}`)
})
}
aboutToAppear(): void {
console.log(`aboutToAppear in child: ${this.cUserInfo.name}`)
this.cUserInfo.name = "aboutToAppear in child"
}
aboutToDisappear(): void {
console.log(`aboutToDisappear in child: ${this.cUserInfo.name}`)
this.cUserInfo.name = "aboutToDisappear in child"
}
build() {
Column({space: 10}) {
Text(`cName: ${this.cUserInfo.name}`)
}
.width('100%')
}
}
less
03-15 10:12:11.826 29071-29071 A00000/testTag apppool I Succeeded in loading the content.
03-15 10:12:11.830 29071-29071 A03d00/JSAPP apppool I aboutToAppear in child: 孙膑
03-15 10:12:11.830 29071-29071 A03d00/JSAPP apppool I In Fathor monitor: userInfo.name, before:"孙膑",
03-15 10:12:11.830 29071-29071 A03d00/JSAPP apppool I now:"aboutToAppear in child"
03-15 10:12:11.830 29071-29071 A03d00/JSAPP apppool I In Child monitor:cUserInfo.name, before:孙膑, now:aboutToAppear in child
03-15 10:12:23.669 29071-29071 A03d00/JSAPP com.examp...lication I In Fathor monitor: userInfo.name, before:"aboutToAppear in child",
03-15 10:12:23.669 29071-29071 A03d00/JSAPP com.examp...lication I now:"1742004743669"
03-15 10:12:23.669 29071-29071 A03d00/JSAPP com.examp...lication I In Child monitor:cUserInfo.name, before:aboutToAppear in child, now:1742004743669
03-15 10:12:29.272 29071-29071 A03d00/JSAPP com.examp...lication I aboutToDisappear in child: 1742004743669
03-15 10:12:29.272 29071-29071 A03d00/JSAPP com.examp...lication I In Fathor monitor: userInfo.name, before:"1742004743669",
03-15 10:12:29.272 29071-29071 A03d00/JSAPP com.examp...lication I now:"aboutToDisappear in child"
03-15 10:12:29.272 29071-29071 A03d00/JSAPP com.examp...lication I In Child monitor:cUserInfo.name, before:1742004743669, now:aboutToDisappear in child
03-15 10:12:34.398 29071-29071 A03d00/JSAPP com.examp...lication I In Fathor monitor: userInfo.name, before:"aboutToDisappear in child",
03-15 10:12:34.398 29071-29071 A03d00/JSAPP com.examp...lication I now:"1742004754398"
拆解:
- 当创建子组件的时候,在aboutToAppear 的时候,
@Monitor
就会监听变量的变化。
less
03-15 10:12:11.830 29071-29071 A03d00/JSAPP apppool I aboutToAppear in child: 孙膑
03-15 10:12:11.830 29071-29071 A03d00/JSAPP apppool I In Fathor monitor: userInfo.name, before:"孙膑",
03-15 10:12:11.830 29071-29071 A03d00/JSAPP apppool I now:"aboutToAppear in child"
03-15 10:12:11.830 29071-29071 A03d00/JSAPP apppool I In Child monitor:cUserInfo.name, before:孙膑, now:aboutToAppear in child
- 当点击'change name' 按钮的时候,更改
@Trace
装饰的变量,触发父组件和子组件的监听回调。
less
03-15 10:12:23.669 29071-29071 A03d00/JSAPP com.examp...lication I In Fathor monitor: userInfo.name, before:"aboutToAppear in child",
03-15 10:12:23.669 29071-29071 A03d00/JSAPP com.examp...lication I now:"1742004743669"
03-15 10:12:23.669 29071-29071 A03d00/JSAPP com.examp...lication I In Child monitor:cUserInfo.name, before:aboutToAppear in child, now:1742004743669
- 隐藏子组件的时候,在子组件aboutToDisappear 中修改
@Trace
装饰的变量,会触发父组件和子组件的监听回调
less
03-15 10:12:29.272 29071-29071 A03d00/JSAPP com.examp...lication I aboutToDisappear in child: 1742004743669
03-15 10:12:29.272 29071-29071 A03d00/JSAPP com.examp...lication I In Fathor monitor: userInfo.name, before:"1742004743669",
03-15 10:12:29.272 29071-29071 A03d00/JSAPP com.examp...lication I now:"aboutToDisappear in child"
03-15 10:12:29.272 29071-29071 A03d00/JSAPP com.examp...lication I In Child monitor:cUserInfo.name, before:1742004743669, now:aboutToDisappear in child
- 再次更新属性变量的值,看到只有父组件有监听回调,子组件无监听回调。说明子组件已经移除监听。
arduino
03-15 10:12:34.398 29071-29071 A03d00/JSAPP com.examp...lication I In Fathor monitor: userInfo.name, before:"aboutToDisappear in child",
03-15 10:12:34.398 29071-29071 A03d00/JSAPP com.examp...lication I now:"1742004754398"
关键点:
- 监听起点:
@Monitor
在子组件的aboutToAppear
生命周期中开始监听变量变化。
- 监听范围:
- 父组件和子组件中的
@Monitor
回调均会被触发,便于跨组件状态管理。
- 监听终点:
- 子组件销毁后,其
@Monitor
监听被移除,仅父组件的回调会被触发。
- 生命周期一致性:
@Monitor
的监听生命周期与组件的生命周期一致,确保状态管理的准确性和高效性。