DEV Community

Cover image for HarmonyOS Development: V2 Version Decorator @ Monitor Decorator
程序员一鸣
程序员一鸣

Posted on

HarmonyOS Development: V2 Version Decorator @ Monitor Decorator

Foreword


this article code case based on api13.


With the official iteration, in the new Api, for new application development, the official has suggested to directly use the decorator to which V2 belongs for development, so, if you can get started with V2, try to get started with V2, after all, V2 is an enhanced version of V1 that provides more features and flexibility for developers, the upgrade from V1 to V2 is definitely the general trend. However, after all, V1 has a large number of application bases and is widely used. If V1 version function and performance have been able to meet the needs, in fact, there is no need to switch, in a word: for new applications, V2 should be used as much as possible. For old applications, V2 may not be switched if V1 is satisfied. If functions are limited, it is recommended to switch step by step.

This article mainly summarizes the @ Monitor decorator in the V2 version decorator, which is targeted the @ Watch decorator in V1 is different in use and function.

Remember that when writing the refresh component, there was a function that needed to monitor the current refresh or load shutdown status, and then execute the shutdown animation and Other Logic. The @ Watch decorator was used. The simple logic is as follows:

class RefreshController {
closeRefresh: boolean = false
closeLoadMore: boolean = false
}
@Entry
@Component
struct Index {
@State @Watch("listenerController") refreshController: RefreshController = new RefreshController()
listenerController() {
Console.log ("==current refresh status:"+this. refreshController. closeRefresh)
Console.log ("==Current loading status:"+this. refreshController. closeLoadMore)
}
build() {
Column() {
Button ("Turn off refresh")
.onClick(() => {
this.refreshController.closeRefresh = true
})
Button ("Close Load")
.margin({ top: 20 })
.onClick(() => {
this.refreshController.closeLoadMore = true
})
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
Enter fullscreen mode Exit fullscreen mode

after running, we click on the button to print the log:

Image description

although we can monitor the execution status through the @ Watch decorator and realize our logic, there is a problem. We only want to monitor the change of a certain status, such as only monitoring the Refresh status or only monitoring the loading status. However, the @ Watch decorator is that no matter which one you monitor, you will return it to you, which obviously will affect our targeted logical judgment.

In addition, there is a problem, what is the value of the variable before the change cannot be obtained here, and in a scenario with complex business logic, we cannot know exactly which attribute or element has changed to trigger the @ Watch event, which is very inconvenient for us to monitor the change of the variable accurately.

In view of the above disadvantages, the @ Monitor decorator in V2 version makes up for this defect by monitoring the change of a single attribute or array item in an object or array, and can obtain the value before the change.

After changing to the @ Monitor decorator, listen separately for the property.

@ObservedV2
class RefreshController {
@Trace closeRefresh: boolean = false
@Trace closeLoadMore: boolean = false
}
@Entry
@ComponentV2
struct Index {
@Local refreshController: RefreshController = new RefreshController()
@Monitor("refreshController.closeRefresh")
closeRefreshChange() {
Console.log ("==current refresh status:"+this. refreshController. closeRefresh)
}
@Monitor("refreshController.closeLoadMore")
closeLoadMoreChange() {
Console.log ("==Current loading status:"+this. refreshController. closeLoadMore)
}
build() {
Column() {
Button ("Turn off refresh")
.onClick(() => {
this.refreshController.closeRefresh = true
})
Button ("Close Load")
.margin({ top: 20 })
.onClick(() => {
this.refreshController.closeLoadMore = true
})
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
Enter fullscreen mode Exit fullscreen mode

Mode of use

first of all, it should be noted that the variables monitored by @ Monitor must be decorated with @ Local, @ Param, @ Provider, @ Consumer, @ Computed, otherwise they cannot be monitored. This must be noted.

In the first step, use one of @ Local, @ Param, @ Provider, @ Consumer, @ Computed, etc. to modify your variables, for example, the following code:

@Local testContent: string="Test Data One"
Enter fullscreen mode Exit fullscreen mode

in the second step, use the @ Monitor decorator to Monitor. The method name is defined by itself. It is required that @ Monitor("variable name"), where the variable name must be consistent with the variable name in the first step, for example, the following code:

@Monitor("testContent")
testContentChange() {
Console.log ("==attribute testContent changed:"+this. testContent)
}
Enter fullscreen mode Exit fullscreen mode

dynamically changing the property testContent will trigger the function decorated by the @ Monitor decorator. @ Monitor decorator supports listen to multiple state variables, directly separated by commas, multiple properties, any property changes will be called back.

@Monitor("testContent","testNumber")
testChange() {
    console.log("==testContent:" + this.testContent + ",testNumber:" + this.testNumber)
  }
Enter fullscreen mode Exit fullscreen mode

Get the value before the change

If you want to get the value before the current property changes, you need to pass it in the function. A parameter of type IMonitor.

A variable of type IMonitor is used as an argument to the @ Monitor decoration method.

Property type parameters return Value description
dirty Array none none save the changed property name.
value function path? : string IMonitorValue obtain the change information of the specified attribute (path). If path is not specified, the change information of the first property changed in the listening order of @ Monitor is returned.

MonitorValue type

IMonitorValue the type stores information about the property change, including the property name, the value before the change, and the current value.

Property type description
before T the value of the listener property before it changes.
now T the current value after the listening property changes.
path string the name of the property to listen.
  @Monitor("testContent")
  testChange(monitor: IMonitor) {
    monitor.dirty.forEach((path: string) => {
      console.log("==:" + monitor.value(path)?.before + ",:" + monitor.value(path)?.now)
    })
  }
Enter fullscreen mode Exit fullscreen mode

If you only want to listen for the changed value, the IMonitor parameter can be omitted.

Object Listener

in the foreword, we can see that when listening for property changes in an object, we need to use @ Trace decoration cannot be monitored if it is not decorated, so in actual development, if you need to monitor a single attribute of an object, @ Trace decoration must be used.

If it is not decorated, then the object needs to be recreated. Although this method can also be monitored normally, it is not the only attribute monitoring and is not recommend in actual development.

The following cases do not use the @ Trace decoration and are not recommended.

class RefreshController {
closeRefresh: boolean = false
closeLoadMore: boolean = false
}
@Entry
@ComponentV2
struct Index {
@Local refreshController: RefreshController = new RefreshController()
@Monitor("refreshController.closeRefresh")
closeRefreshChange() {
Console.log ("==current refresh status:"+this. refreshController. closeRefresh)
}
@Monitor("refreshController.closeLoadMore")
closeLoadMoreChange() {
Console.log ("==Current loading status:"+this. refreshController. closeLoadMore)
}
build() {
Column() {
Button ("Turn off refresh")
.onClick(() => {
this.refreshController = new RefreshController()
this.refreshController.closeRefresh = true
})
Button ("Close Load")
.margin({ top: 20 })
.onClick(() => {
this.refreshController = new RefreshController()
this.refreshController.closeLoadMore = true
})
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
Enter fullscreen mode Exit fullscreen mode

If you want to listen for property changes across an object, @ Trace decoration can not be used.

class RefreshController {
closeRefresh: boolean = false
closeLoadMore: boolean = false
}
@Entry
@ComponentV2
struct Index {
@Local refreshController: RefreshController = new RefreshController()
@Monitor("refreshController")
statusChange() {
Console.log ("==current refresh status:"+this. refreshController. closeRefresh)
Console.log ("==Current loading status:"+this. refreshController. closeLoadMore)
}
build() {
Column() {
Button ("Turn off refresh")
.onClick(() => {
this.refreshController = new RefreshController()
this.refreshController.closeRefresh = true
})
Button ("Close Load")
.margin({ top: 20 })
.onClick(() => {
this.refreshController = new RefreshController()
this.refreshController.closeLoadMore = true
})
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
Enter fullscreen mode Exit fullscreen mode

In addition to listening in the UI component, you can also listen in its own object to facilitate some logic in the object, also supported in in the inheritance class scenario, the same attribute is monitored multiple times.

@ObservedV2
class RefreshController {
@Trace closeRefresh: boolean = false
@Trace closeLoadMore: boolean = false
@Monitor("closeRefresh")
closeRefreshChange() {
Console.log ("==current refresh status in listener object:"+this. closeRefresh)
}
}
Enter fullscreen mode Exit fullscreen mode

General listening capability

@ Monitor decorator, in addition to normal data monitoring, also supports monitoring elements in arrays, including multi-dimensional arrays and object arrays. Although it can normally Monitor changes in its values, it cannot Monitor changes caused by API calls of built-in types (Array, Map, Date, Set).

It is also important to note that when @ Monitor listens to the overall change of the array, it can only judge whether the array has changes such as insertion and deletion by listening to the length change of the array. The following is a simple case of two-bit array data change:

@Entry
@ComponentV2
struct Index {
@Local numberArray: number[][] = [[1, 1, 1], [2, 2, 2], [3, 3, 3]];
@Monitor("numberArray.0.0", "numberArray.1.1")
statusChange() {
Console.log ("==Data Change:"+this. umberArray)
}
build() {
Column() {
Button ("Change")
.onClick(() => {
this.numberArray[0][0]++
})
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
Enter fullscreen mode Exit fullscreen mode

the above cases can be found. As long as the data changes, the data monitoring method will be executed.

Listening when the object as a whole changes, if the current property has not changed, the @ Monitor callback is not triggered.

In the following case, clicking the buttons in turn will happen. Button 1 will not execute any method, because the value of the attribute is the same and has not changed. Button 2 and Button 3 can execute normally.

@ObservedV2
class RefreshController {
@Trace closeRefresh: boolean = false
@Trace closeLoadMore: boolean = false
constructor(closeRefresh: boolean, closeLoadMore: boolean) {
this.closeRefresh = closeRefresh;
this.closeLoadMore = closeLoadMore;
}
}
@Entry
@ComponentV2
struct Index {
@Local refreshController: RefreshController = new RefreshController(false, false)
@Monitor("refreshController.closeRefresh")
closeRefreshChange() {
Console.log ("==current refresh status:"+this. refreshController. closeRefresh)
}
@Monitor("refreshController.closeLoadMore")
closeLoadMoreChange() {
Console.log ("==Current loading status:"+this. refreshController. closeLoadMore)
}
build() {
Column() {
Button ("won't leave")
.onClick(() => {
this.refreshController = new RefreshController(false, false)
})
Button ("Turn off refresh")
.margin({ top: 20 })
.onClick(() => {
this.refreshController = new RefreshController(true, false)
})
Button ("Close Load")
.margin({ top: 20 })
.onClick(() => {
this.refreshController = new RefreshController(false, true)
})
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
Enter fullscreen mode Exit fullscreen mode

Related Summary

if you want to implement @ Monitor monitoring, its variables must be decorated with @ Local, @ Param, @ Provider, @ Consumer, @ Computed, and cannot be monitored without modification. Also, if the monitoring object changes, then it is not recommended to Monitor the same attribute multiple times in a class. Only The Last defined listening method is valid.

Top comments (0)