1# \@Track Decorator: Class Object Property-level Update 2 3 4\@Track is a decorator used to decorate properties of class objects. When a property decorated by \@Track changes, only the UI associated with the property is updated. 5 6 7> **NOTE** 8> 9> Since API version 11, this decorator is supported in ArkTS widgets. 10 11 12## Overview 13 14\@Track enables property-level UI updates. When a property of a class object is decorated by \@Track, changes to the property will trigger only updates to the UI associated with the property. Properties not decorated by \@Track cannot be used in the UI. 15 16 17## Decorator Description 18 19| \@Track Decorator | Description | 20| ------------------ | -------------------- | 21| Decorator parameters | None.| 22| Allowed variable types| Non-static properties of class objects.| 23 24## Observed Changes and Behavior 25 26When a class object is a state variable, any changes to its properties decorated by \@Track will trigger only updates to the UI associated with those properties. 27 28> **NOTE** 29> 30> When no property in the class object is decorated with \@Track, the behavior remains unchanged. \@Track is unable to observe changes of nested objects. 31 32Using the @Track decorator can avoid redundant re-renders. 33 34```ts 35class LogTrack { 36 @Track str1: string; 37 @Track str2: string; 38 39 constructor(str1: string) { 40 this.str1 = str1; 41 this.str2 = 'World'; 42 } 43} 44 45class LogNotTrack { 46 str1: string; 47 str2: string; 48 49 constructor(str1: string) { 50 this.str1 = str1; 51 this.str2 = 'World'; 52 } 53} 54 55@Entry 56@Component 57struct AddLog { 58 @State logTrack: LogTrack = new LogTrack('Hello'); 59 @State logNotTrack: LogNotTrack = new LogNotTrack('Hello'); 60 61 isRender(index: number) { 62 console.log(`Text ${index} is rendered`); 63 return 50; 64 } 65 66 build() { 67 Row() { 68 Column() { 69 Text(this.logTrack.str1) // UINode1 70 .fontSize(this.isRender(1)) 71 .fontWeight(FontWeight.Bold) 72 Text(this.logTrack.str2) // UINode2 73 .fontSize(this.isRender(2)) 74 .fontWeight(FontWeight.Bold) 75 Button('change logTrack.str1') 76 .onClick(() => { 77 this.logTrack.str1 = 'Bye'; 78 }) 79 Text(this.logNotTrack.str1) // UINode3 80 .fontSize(this.isRender(3)) 81 .fontWeight(FontWeight.Bold) 82 Text(this.logNotTrack.str2) // UINode4 83 .fontSize(this.isRender(4)) 84 .fontWeight(FontWeight.Bold) 85 Button('change logNotTrack.str1') 86 .onClick(() => { 87 this.logNotTrack.str1 = 'Goodbye'; 88 }) 89 } 90 .width('100%') 91 } 92 .height('100%') 93 } 94} 95``` 96 97In the preceding example: 98 991. All attributes in the **LogTrack** class are decorated by @Track. After the **change logTrack.str1** button is clicked, **UINode1** is re-rendered, but **UINode2** is not, as indicated by that only one log record is generated. 100```ts 101Text 1 is rendered 102``` 103 1042. None of the attributes in the **logNotTrack** class is decorated by @Track. After the **change logTrack.str1** button is clicked, both **UINode3** and **UINode4** are re-rendered, as indicated by that two log records are generated. Redundant re-renders occur. 105```ts 106Text 3 is rendered 107Text 4 is rendered 108``` 109 110## Constraints 111 112- Properties that are not decorated by \@Track cannot be used in the UI, which means that such properties cannot be bound to components or be used to initialize child components. Incorrect use will cause JavaScript crashes. Yet, these properties can be used in non-UI cases, such as event callback functions and lifecycle functions. 113 114- Whenever possible, avoid any combination of class objects that contain \@Track and those that do not in, for example, union types and class inheritance. 115 116 117## Usage Scenarios 118 119### \@Track and Custom Component Updates 120 121This example is used to clarify the processing steps of custom component updates and \@Track. The **log** object is a state variable decorated by \@State. Its **logInfo** property is decorated by \@Track, but other properties are not, and the values of these other properties are not updated through the UI. 122 123 124```ts 125class Log { 126 @Track logInfo: string; 127 owner: string; 128 id: number; 129 time: Date; 130 location: string; 131 reason: string; 132 133 constructor(logInfo: string) { 134 this.logInfo = logInfo; 135 this.owner = 'OH'; 136 this.id = 0; 137 this.time = new Date(); 138 this.location = 'CN'; 139 this.reason = 'NULL'; 140 } 141} 142 143@Entry 144@Component 145struct AddLog { 146 @State log: Log = new Log('origin info.'); 147 148 build() { 149 Row() { 150 Column() { 151 Text(this.log.logInfo) 152 .fontSize(50) 153 .fontWeight(FontWeight.Bold) 154 .onClick(() => { 155 // The properties without @Track can be used in the event handler. 156 console.log('owner: ' + this.log.owner + 157 ' id: ' + this.log.id + 158 ' time: ' + this.log.time + 159 ' location: ' + this.log.location + 160 ' reason: ' + this.log.reason); 161 this.log.time = new Date(); 162 this.log.id++; 163 164 this.log.logInfo += ' info.'; 165 }) 166 } 167 .width('100%') 168 } 169 .height('100%') 170 } 171} 172``` 173 174Processing steps: 175 1761. The click event **Text.onClick** of the **AddLog** custom component increases the value of **info**. 177 1782. In response to the change of the \@State decorated variable **log**, the \@Track decorated property **logInfo** is updated, and the **Text** component is re-rendered. 179