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> This decorator can be used in atomic services since API version 11. 12 13## Overview 14 15An 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. 16 17 18## Decorator Description 19 20| \@Watch Decorator| Description | 21| -------------- | ---------------------------------------- | 22| Decorator parameters | Mandatory. Constant string, which is quoted. Reference to a (string) => void custom component member function.| 23| Custom component variables that can be decorated | All decorated state variables. Regular variables cannot be watched. | 24| Order of decorators | Place the [\@State](./arkts-state.md), [\@Prop](./arkts-prop.md), or [\@Link](./arkts-link.md) decorator in front of the \@Watch decorator.| 25 26 27## Syntax 28 29| Type | Description | 30| ---------------------------------------- | ---------------------------------------- | 31| (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.| 32 33 34## Observed Changes and Behavior 35 361. \@Watch callback is triggered when a change of a state variable (including the change of a key in [AppStorage](./arkts-appstorage.md) and [LocalStorage](./arkts-localstorage.md) that are bound in a two-way manner) is observed. 37 382. The \@Watch callback is executed synchronously after the variable change in the custom component. 39 403. 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. 41 424. 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 change of the custom component variable. 43 44 45## Restrictions 46 47- 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, do not mutate the \@Watch decorated state variable inside the callback handler. 48 49- 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. 50 51- Calling **async await** from an \@Watch function is not recommended, because asynchronous behavior may cause performance issues of re-rendering. 52 53 54## Application Scenarios 55 56### \@Watch and Custom Component Update 57 58This 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**. 59 60 61```ts 62@Component 63struct TotalView { 64 @Prop @Watch('onCountUpdated') count: number = 0; 65 @State total: number = 0; 66 // @Watch callback 67 onCountUpdated(propName: string): void { 68 this.total += this.count; 69 } 70 71 build() { 72 Text(`Total: ${this.total}`) 73 } 74} 75 76@Entry 77@Component 78struct CountModifier { 79 @State count: number = 0; 80 81 build() { 82 Column() { 83 Button('add to basket') 84 .onClick(() => { 85 this.count++ 86 }) 87 TotalView({ count: this.count }) 88 } 89 } 90} 91``` 92 93Processing steps: 94 951. The click event **Button.onClick** of the **CountModifier** custom component increases the value of **count**. 96 972. 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 invoked, which updates the **total** variable in **TotalView**. 98 993. The **Text** component in the child component **TotalView** is re-rendered. 100 101 102### Combination of \@Watch and \@Link 103 104This example illustrates how to watch an \@Link decorated variable in a child component. 105 106 107```ts 108class PurchaseItem { 109 static NextId: number = 0; 110 public id: number; 111 public price: number; 112 113 constructor(price: number) { 114 this.id = PurchaseItem.NextId++; 115 this.price = price; 116 } 117} 118 119@Component 120struct BasketViewer { 121 @Link @Watch('onBasketUpdated') shopBasket: PurchaseItem[]; 122 @State totalPurchase: number = 0; 123 124 updateTotal(): number { 125 let total = this.shopBasket.reduce((sum, i) => sum + i.price, 0); 126 // A discount is provided when the amount exceeds 100 euros. 127 if (total >= 100) { 128 total = 0.9 * total; 129 } 130 return total; 131 } 132 // @Watch callback 133 onBasketUpdated(propName: string): void { 134 this.totalPurchase = this.updateTotal(); 135 } 136 137 build() { 138 Column() { 139 ForEach(this.shopBasket, 140 (item: PurchaseItem) => { 141 Text(`Price: ${item.price.toFixed(2)} €`) 142 }, 143 (item: PurchaseItem) => item.id.toString() 144 ) 145 Text(`Total: ${this.totalPurchase.toFixed(2)} €`) 146 } 147 } 148} 149 150@Entry 151@Component 152struct BasketModifier { 153 @State shopBasket: PurchaseItem[] = []; 154 155 build() { 156 Column() { 157 Button('Add to basket') 158 .onClick(() => { 159 this.shopBasket.push(new PurchaseItem(Math.round(100 * Math.random()))) 160 }) 161 BasketViewer({ shopBasket: $shopBasket }) 162 } 163 } 164} 165``` 166 167Processing steps: 168 1691. **Button.onClick** of the **BasketModifier** component adds an item to **BasketModifier shopBasket**. 170 1712. The value of the \@Link decorated variable **BasketViewer shopBasket** changes. 172 1733. The state management framework calls the \@Watch callback **BasketViewer onBasketUpdated** to update the value of **BasketViewer TotalPurchase**. 174 1754. 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** variable changes, the **Text** component is also re-rendered. Re-rendering happens asynchronously. 176