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?&nbsp;:&nbsp;string)&nbsp;=&gt;&nbsp;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