1# \@Watch Decorator: Getting Notified of State Variable Changes 2 3 4\@Watch is used to listen for state variables. If your application needs watch for value changes of a state variable, you can decorate the variable with \@Watch. 5 6 7> **NOTE** 8> 9> Since API version 9, this decorator is supported in ArkTS widgets. 10 11 12## Overview 13 14An application can request to be notified whenever the value of the \@Watch decorated variable changes. The \@Watch callback is called when the value change has occurred. \@Watch uses strict equality (===) to determine whether a value is updated in the ArkUI framework. If **false** is returned, the \@Watch callback is triggered. 15 16 17## Decorator Description 18 19| \@Watch Decorator| Description | 20| -------------- | ---------------------------------------- | 21| Decorator parameters | Mandatory. Constant string, which is quoted. Reference to a (string) => void custom component member function.| 22| Custom component variables that can be decorated | All decorated state variables. Regular variables cannot be watched. | 23| Order of decorators | It is recommended that the \@State, \@Prop, \@Link, or other decorators precede the \@Watch decorator.| 24 25 26## Syntax 27 28| Type | Description | 29| ---------------------------------------- | ---------------------------------------- | 30| (changedPropertyName? : string) => void | This function is a member function of the custom component. **changedPropertyName** indicates the name of the watched attribute.<br>It is useful when you use the same function as a callback to several watched attributes.<br>It takes the attribute name as a string input parameter and returns nothing.| 31 32 33## Observed Changes and Behavior 34 351. When a state variable change (including the change of the named attribute in AppStorage or LocalStorage) is observed, the corresponding \@Watch callback is triggered. 36 372. \@The Watch callback is executed synchronously after the variable change in the custom component. 38 393. If the \@Watch callback mutates other watched variables, their variable @Watch callbacks in the same and other custom components as well as state updates are triggered. 40 414. A \@Watch function is not called upon custom component variable initialization, because initialization is not considered as variable mutation. A \@Watch function is called upon updating of the custom component variable. 42 43 44## Restrictions 45 46- Pay attention to the risk of infinite loops. Loops can be caused by the \@Watch callback directly or indirectly mutating the same variable. To avoid loops, avoid mutating the \@Watch decorated state variable inside the callback handler. 47 48- Pay attention to performance. The attribute value update function delays component re-render (see the preceding behavior description). The callback should only perform quick computations. 49 50- Calling **async await** from an \@Watch function is not recommended, because asynchronous behavior may cause performance issues of re-rendering. 51 52 53## Application Scenarios 54 55### \@Watch and Custom Component Update 56 57This example is used to clarify the processing steps of custom component updates and \@Watch. **count** is decorated by \@State in **CountModifier** and \@Prop in **TotalView**. 58 59 60```ts 61@Component 62struct TotalView { 63 @Prop @Watch('onCountUpdated') count: number = 0; 64 @State total: number = 0; 65 // @Watch callback 66 onCountUpdated(propName: string): void { 67 this.total += this.count; 68 } 69 70 build() { 71 Text(`Total: ${this.total}`) 72 } 73} 74 75@Entry 76@Component 77struct CountModifier { 78 @State count: number = 0; 79 80 build() { 81 Column() { 82 Button('add to basket') 83 .onClick(() => { 84 this.count++ 85 }) 86 TotalView({ count: this.count }) 87 } 88 } 89} 90``` 91 92Processing steps: 93 941. The click event **Button.onClick** of the **CountModifier** custom component increases the value of **count**. 95 962. In response to the change of the @State decorated variable **count**, \@Prop in the child component **TotalView** is updated, and its **\@Watch('onCountUpdated')** callback is triggered, which updates the **total** variable in **TotalView**. 97 983. The **Text** component in the child component **TotalView** is re-rendered. 99 100 101### Combination of \@Watch and \@Link 102 103This example illustrates how to watch an \@Link decorated variable in a child component. 104 105 106```ts 107class PurchaseItem { 108 static NextId: number = 0; 109 public id: number; 110 public price: number; 111 112 constructor(price: number) { 113 this.id = PurchaseItem.NextId++; 114 this.price = price; 115 } 116} 117 118@Component 119struct BasketViewer { 120 @Link @Watch('onBasketUpdated') shopBasket: PurchaseItem[]; 121 @State totalPurchase: number = 0; 122 123 updateTotal(): number { 124 let total = this.shopBasket.reduce((sum, i) => sum + i.price, 0); 125 // A discount is provided when the amount exceeds 100 euros. 126 if (total >= 100) { 127 total = 0.9 * total; 128 } 129 return total; 130 } 131 // @Watch callback 132 onBasketUpdated(propName: string): void { 133 this.totalPurchase = this.updateTotal(); 134 } 135 136 build() { 137 Column() { 138 ForEach(this.shopBasket, 139 (item:PurchaseItem) => { 140 Text(`Price: ${item.price.toFixed(2)} €`) 141 }, 142 (item:PurchaseItem) => item.id.toString() 143 ) 144 Text(`Total: ${this.totalPurchase.toFixed(2)} €`) 145 } 146 } 147} 148 149@Entry 150@Component 151struct BasketModifier { 152 @State shopBasket: PurchaseItem[] = []; 153 154 build() { 155 Column() { 156 Button('Add to basket') 157 .onClick(() => { 158 this.shopBasket.push(new PurchaseItem(Math.round(100 * Math.random()))) 159 }) 160 BasketViewer({ shopBasket: $shopBasket }) 161 } 162 } 163} 164``` 165 166The processing procedure is as follows: 167 1681. **Button.onClick** of the **BasketModifier** component adds an item to **BasketModifier shopBasket**. 169 1702. The value of the \@Link decorated variable **BasketViewer shopBasket** changes. 171 1723. The state management framework calls the \@Watch callback **BasketViewer onBasketUpdated** to update the value of **BasketViewer TotalPurchase**. 173 1744. Because \@Link decorated shopBasket changes (a new item is added), the ForEach component executes the item Builder to render and build the new item. Because the @State decorated totalPurchase variables changes, the **Text** component is also re-rendered. Re-rendering happens asynchronously. 175