1e41f4b71Sopenharmony_ci# \@State Decorator: State Owned by Component
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ciAn \@State decorated variable, also called a state variable, is a variable that holds the state property and is used to render the owning custom component. When it changes, the UI is re-rendered accordingly.
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciAmong the decorators related to state variables, \@State is the most basic decorator, as it is the one that empowers variables to have the state property. It is also the data source of most state variables.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ci> **NOTE**
11e41f4b71Sopenharmony_ci>
12e41f4b71Sopenharmony_ci> This decorator can be used in ArkTS widgets since API version 9.
13e41f4b71Sopenharmony_ci>
14e41f4b71Sopenharmony_ci> This decorator can be used in atomic services since API version 11.
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ci## Overview
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ciAn @State decorated variable, like all other decorated variables in the declarative paradigm, are private and only accessible from within the component. Its type and its local initialization must be specified. Initialization from the parent component using the named parameter mechanism is accepted.
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci\@State decorated variables have the following features:
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ci- A one-way synchronization relationship can be set up from an \@State decorated variable to an \@Prop decorated variable in a child component, and a two-way synchronization relationship to an \@Link or \@ObjectLink decorated variable.
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ci- The lifecycle of the \@State decorated variable is the same as that of its owning custom component.
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ci## Rules of Use
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ci| \@State Decorator | Description                                                        |
30e41f4b71Sopenharmony_ci| ------------------ | ------------------------------------------------------------ |
31e41f4b71Sopenharmony_ci| Decorator parameters        | None.                                                          |
32e41f4b71Sopenharmony_ci| Synchronization type          | Does not synchronize with any type of variable in the parent component.                            |
33e41f4b71Sopenharmony_ci| Allowed variable types| Object, class, string, number, Boolean, enum, and array of these types.<br>Date type.<br>(Applicable to API version 11 or later) [Map](#decorating-variables-of-the-map-type) or [Set](#decorating-variables-of-the-set-type) type.<br>**undefined** or **null**.<br>Union types defined by the ArkUI framework, for example, [Length](../reference/apis-arkui/arkui-ts/ts-types.md#length), [ResourceStr](../reference/apis-arkui/arkui-ts/ts-types.md#resourcestr) and [ResourceColor](../reference/apis-arkui/arkui-ts/ts-types.md#resourcecolor).<br>The type must be specified.<br>For details about the scenarios of supported types, see [Observed Changes](#observed-changes).<br>**any** is not supported.<br>(Applicable to API version 11 or later) Union type of the preceding types, for example, **string \| number**, **string \| undefined** or **ClassA \| null**. For details, see [Union Type](#union-type).<br>**NOTE**<br>When **undefined** or **null** is used, you are advised to explicitly specify the type to pass the TypeScript type check. For example, **@State a : string \| undefined = undefined** is recommended; **@State a: string = undefined** is not recommended. |
34e41f4b71Sopenharmony_ci| Initial value for the decorated variable| Local initialization is required.                                              |
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci## Variable Transfer/Access Rules
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci| Transfer/Access         | Description                                                        |
40e41f4b71Sopenharmony_ci| ------------------ | ------------------------------------------------------------ |
41e41f4b71Sopenharmony_ci| Initialization from the parent component    | Optional. Initialization from the parent component or local initialization can be used. The initial value specified in the parent component will overwrite the one defined locally.<br>Supports normal variables (value changes to the @State by normal variables trigger only initialization. Changes to the state variables can trigger UI re-rendering), \@State, [\@Link](arkts-link.md), [\@Prop](arkts-prop.md), [\@Provide](arkts-provide-and-consume.md), [\@Consume](arkts-provide-and-consume.md), [\@ObjectLink](arkts-observed-and-objectlink.md), [\@StorageLink](arkts-appstorage.md#storagelink), [\@StorageProp](arkts-appstorage.md#storageprop), and [\@LocalStorageLink](arkts-localstorage.md#localstoragelink) and [\@LocalStorageProp](arkts-localstorage.md#localstorageprop) decorated variables in the parent component to initialize the \@State of the child component.|
42e41f4b71Sopenharmony_ci| Child component initialization  | Supported. An \@State decorated variable can be used to initialize a regular variable or \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component.|
43e41f4b71Sopenharmony_ci| Access from outside the component| Private, accessible only within the component.                                  |
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci  **Figure 1** Initialization rule 
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ci![en-us_image_0000001502091796](figures/en-us_image_0000001502091796.png)
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ci## Observed Changes and Behavior
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ciNot all changes to state variables cause UI updates. Only changes that can be observed by the framework do. This section describes what changes can be observed and how the framework triggers UI updates after the changes are observed, that is, how the framework behaves.
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci### Observed Changes
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ci- When the decorated variable is of the Boolean, string, or number type, its value change can be observed.
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ci  ```ts
60e41f4b71Sopenharmony_ci  // for simple type
61e41f4b71Sopenharmony_ci  @State count: number = 0;
62e41f4b71Sopenharmony_ci  // value changing can be observed
63e41f4b71Sopenharmony_ci  this.count = 1;
64e41f4b71Sopenharmony_ci  ```
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci- When the decorated variable is of the class or Object type, its value change and value changes of all its properties, that is, the properties that **Object.keys(observedObject)** returns, can be observed. Below is an example.
67e41f4b71Sopenharmony_ci    Declare the **ClassA** and **Model** classes.
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci    ```ts
70e41f4b71Sopenharmony_ci      class ClassA {
71e41f4b71Sopenharmony_ci        public value: string;
72e41f4b71Sopenharmony_ci      
73e41f4b71Sopenharmony_ci        constructor(value: string) {
74e41f4b71Sopenharmony_ci          this.value = value;
75e41f4b71Sopenharmony_ci        }
76e41f4b71Sopenharmony_ci      }
77e41f4b71Sopenharmony_ci      
78e41f4b71Sopenharmony_ci      class Model {
79e41f4b71Sopenharmony_ci        public value: string;
80e41f4b71Sopenharmony_ci        public name: ClassA;
81e41f4b71Sopenharmony_ci        constructor(value: string, a: ClassA) {
82e41f4b71Sopenharmony_ci          this.value = value;
83e41f4b71Sopenharmony_ci          this.name = a;
84e41f4b71Sopenharmony_ci        }
85e41f4b71Sopenharmony_ci      }
86e41f4b71Sopenharmony_ci    ```
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ci    Use \@State to decorate a variable of the Model class object type.
89e41f4b71Sopenharmony_ci
90e41f4b71Sopenharmony_ci    ```ts
91e41f4b71Sopenharmony_ci    // Class type
92e41f4b71Sopenharmony_ci    @State title: Model = new Model('Hello', new ClassA('World'));
93e41f4b71Sopenharmony_ci    ```
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ci    Assign a value to the \@State decorated variable.
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci    ```ts
98e41f4b71Sopenharmony_ci    // Assign a value to the class object.
99e41f4b71Sopenharmony_ci    this.title = new Model('Hi', new ClassA('ArkUI'));
100e41f4b71Sopenharmony_ci    ```
101e41f4b71Sopenharmony_ci
102e41f4b71Sopenharmony_ci    Assign a value to a property of the \@State decorated variable.
103e41f4b71Sopenharmony_ci
104e41f4b71Sopenharmony_ci    ```ts
105e41f4b71Sopenharmony_ci    // Assign a value to a property of the class object.
106e41f4b71Sopenharmony_ci    this.title.value = 'Hi';
107e41f4b71Sopenharmony_ci    ```
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci    The value assignment of the nested property cannot be observed.
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci    ```ts
112e41f4b71Sopenharmony_ci    // The value assignment of the nested property cannot be observed.
113e41f4b71Sopenharmony_ci    this.title.name.value = 'ArkUI';
114e41f4b71Sopenharmony_ci    ```
115e41f4b71Sopenharmony_ci- When the decorated variable is of the array type, the addition, deletion, and updates of array items can be observed. Below is an example.
116e41f4b71Sopenharmony_ci  Declare the **Model** class.
117e41f4b71Sopenharmony_ci
118e41f4b71Sopenharmony_ci  ```ts
119e41f4b71Sopenharmony_ci  class Model {
120e41f4b71Sopenharmony_ci    public value: number;
121e41f4b71Sopenharmony_ci    constructor(value: number) {
122e41f4b71Sopenharmony_ci      this.value = value;
123e41f4b71Sopenharmony_ci    }
124e41f4b71Sopenharmony_ci  }
125e41f4b71Sopenharmony_ci  ```
126e41f4b71Sopenharmony_ci
127e41f4b71Sopenharmony_ci  Use \@State to decorate a variable of the Model class array type.
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci  ```ts
130e41f4b71Sopenharmony_ci  // Array type
131e41f4b71Sopenharmony_ci  @State title: Model[] = [new Model(11), new Model(1)];
132e41f4b71Sopenharmony_ci  ```
133e41f4b71Sopenharmony_ci
134e41f4b71Sopenharmony_ci  The value assignment of the array itself can be observed.
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ci  ```ts
137e41f4b71Sopenharmony_ci  // Value assignment of the array
138e41f4b71Sopenharmony_ci  this.title = [new Model(2)];
139e41f4b71Sopenharmony_ci  ```
140e41f4b71Sopenharmony_ci
141e41f4b71Sopenharmony_ci  The value assignment of array items can be observed.
142e41f4b71Sopenharmony_ci
143e41f4b71Sopenharmony_ci  ```ts
144e41f4b71Sopenharmony_ci  // Value assignment of an array item
145e41f4b71Sopenharmony_ci  this.title[0] = new Model(2);
146e41f4b71Sopenharmony_ci  ```
147e41f4b71Sopenharmony_ci
148e41f4b71Sopenharmony_ci  The deletion of array items can be observed.
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci  ```ts
151e41f4b71Sopenharmony_ci  // Array item change
152e41f4b71Sopenharmony_ci  this.title.pop();
153e41f4b71Sopenharmony_ci  ```
154e41f4b71Sopenharmony_ci
155e41f4b71Sopenharmony_ci  The addition of array items can be observed.
156e41f4b71Sopenharmony_ci
157e41f4b71Sopenharmony_ci  ```ts
158e41f4b71Sopenharmony_ci  // Array item change
159e41f4b71Sopenharmony_ci  this.title.push(new Model(12));
160e41f4b71Sopenharmony_ci  ```
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci  The property value assignment in the array items cannot be observed.
163e41f4b71Sopenharmony_ci
164e41f4b71Sopenharmony_ci  ```ts
165e41f4b71Sopenharmony_ci  // The value assignment of the nested property cannot be observed.
166e41f4b71Sopenharmony_ci  this.title[0].value = 6;
167e41f4b71Sopenharmony_ci  ```
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci- When the decorated variable is of the Date type, the overall value assignment of the **Date** object can be observed, and the following APIs can be called to update **Date** properties: **setFullYear**, **setMonth**, **setDate**, **setHours**, **setMinutes**, **setSeconds**, **setMilliseconds**, **setTime**, **setUTCFullYear**, **setUTCMonth**, **setUTCDate**, **setUTCHours**, **setUTCMinutes**, **setUTCSeconds**, and **setUTCMilliseconds**.
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci  ```ts
172e41f4b71Sopenharmony_ci  @Entry
173e41f4b71Sopenharmony_ci  @Component
174e41f4b71Sopenharmony_ci  struct DatePickerExample {
175e41f4b71Sopenharmony_ci    @State selectedDate: Date = new Date('2021-08-08');
176e41f4b71Sopenharmony_ci  
177e41f4b71Sopenharmony_ci    build() {
178e41f4b71Sopenharmony_ci      Column() {
179e41f4b71Sopenharmony_ci        Button('set selectedDate to 2023-07-08')
180e41f4b71Sopenharmony_ci          .margin(10)
181e41f4b71Sopenharmony_ci          .onClick(() => {
182e41f4b71Sopenharmony_ci            this.selectedDate = new Date('2023-07-08');
183e41f4b71Sopenharmony_ci          })
184e41f4b71Sopenharmony_ci        Button('increase the year by 1')
185e41f4b71Sopenharmony_ci          .margin(10)
186e41f4b71Sopenharmony_ci          .onClick(() => {
187e41f4b71Sopenharmony_ci            this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1);
188e41f4b71Sopenharmony_ci          })
189e41f4b71Sopenharmony_ci        Button('increase the month by 1')
190e41f4b71Sopenharmony_ci          .margin(10)
191e41f4b71Sopenharmony_ci          .onClick(() => {
192e41f4b71Sopenharmony_ci            this.selectedDate.setMonth(this.selectedDate.getMonth() + 1);
193e41f4b71Sopenharmony_ci          })
194e41f4b71Sopenharmony_ci        Button('increase the day by 1')
195e41f4b71Sopenharmony_ci          .margin(10)
196e41f4b71Sopenharmony_ci          .onClick(() => {
197e41f4b71Sopenharmony_ci            this.selectedDate.setDate(this.selectedDate.getDate() + 1);
198e41f4b71Sopenharmony_ci          })
199e41f4b71Sopenharmony_ci        DatePicker({
200e41f4b71Sopenharmony_ci          start: new Date('1970-1-1'),
201e41f4b71Sopenharmony_ci          end: new Date('2100-1-1'),
202e41f4b71Sopenharmony_ci          selected: this.selectedDate
203e41f4b71Sopenharmony_ci        })
204e41f4b71Sopenharmony_ci      }.width('100%')
205e41f4b71Sopenharmony_ci    }
206e41f4b71Sopenharmony_ci  }
207e41f4b71Sopenharmony_ci  ```
208e41f4b71Sopenharmony_ci
209e41f4b71Sopenharmony_ci- When the decorated variable is **Map**, value changes of **Map** can be observed. In addition, you can call the **set**, **clear**, and **delete** APIs of **Map** to update its value. For details, see [Decorating Variables of the Map Type](#decorating-variables-of-the-map-type).
210e41f4b71Sopenharmony_ci
211e41f4b71Sopenharmony_ci- When the decorated variable is **Set**, value changes of **Set** can be observed. In addition, you can call the **add**, **clear**, and **delete** APIs of **Set** to update its value. For details, see [Decorating Variables of the Set Type](#decorating-variables-of-the-set-type).
212e41f4b71Sopenharmony_ci
213e41f4b71Sopenharmony_ci### Framework Behavior
214e41f4b71Sopenharmony_ci
215e41f4b71Sopenharmony_ci- When a state variable is changed, the framework searches for components that depend on this state variable.
216e41f4b71Sopenharmony_ci
217e41f4b71Sopenharmony_ci- The framework executes an update method of the dependent components, which triggers re-rendering of the components.
218e41f4b71Sopenharmony_ci
219e41f4b71Sopenharmony_ci- Components or UI descriptions irrelevant to the state variable are not re-rendered, thereby implementing on-demand page updates.
220e41f4b71Sopenharmony_ci
221e41f4b71Sopenharmony_ci
222e41f4b71Sopenharmony_ci## Application Scenarios
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ci
225e41f4b71Sopenharmony_ci### Decorating Variables of Simple Types
226e41f4b71Sopenharmony_ci
227e41f4b71Sopenharmony_ciIn this example, \@State is used to decorate the **count** variable of the simple type, turning it into a state variable. The change of **count** causes the update of the **Button** component.
228e41f4b71Sopenharmony_ci
229e41f4b71Sopenharmony_ci- When **count** changes, the framework searches for components bound to it, which include only the **Button** component in this example.
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_ci- The framework executes the update method of the **Button** component to implement on-demand update.
232e41f4b71Sopenharmony_ci
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci```ts
235e41f4b71Sopenharmony_ci@Entry
236e41f4b71Sopenharmony_ci@Component
237e41f4b71Sopenharmony_cistruct MyComponent {
238e41f4b71Sopenharmony_ci  @State count: number = 0;
239e41f4b71Sopenharmony_ci
240e41f4b71Sopenharmony_ci  build() {
241e41f4b71Sopenharmony_ci    Button(`click times: ${this.count}`)
242e41f4b71Sopenharmony_ci      .onClick(() => {
243e41f4b71Sopenharmony_ci        this.count += 1;
244e41f4b71Sopenharmony_ci      })
245e41f4b71Sopenharmony_ci  }
246e41f4b71Sopenharmony_ci}
247e41f4b71Sopenharmony_ci```
248e41f4b71Sopenharmony_ci
249e41f4b71Sopenharmony_ci
250e41f4b71Sopenharmony_ci### Decorating Variables of the Class Object Type
251e41f4b71Sopenharmony_ci
252e41f4b71Sopenharmony_ci- In this example, \@State is used to decorate the variables **count** and **title** in the custom component **MyComponent**. The type of **title** is **Model**, a custom class. If the value of **count** or **title** changes, the framework searches for all **MyComponent** instances that depend on these variables and triggers re-rendering of them.
253e41f4b71Sopenharmony_ci
254e41f4b71Sopenharmony_ci- The **EntryComponent** has multiple **MyComponent** instances. The internal state change of the first **MyComponent** instance does not affect the second **MyComponent** instance.
255e41f4b71Sopenharmony_ci
256e41f4b71Sopenharmony_ci
257e41f4b71Sopenharmony_ci
258e41f4b71Sopenharmony_ci```ts
259e41f4b71Sopenharmony_ciclass Model {
260e41f4b71Sopenharmony_ci  public value: string;
261e41f4b71Sopenharmony_ci
262e41f4b71Sopenharmony_ci  constructor(value: string) {
263e41f4b71Sopenharmony_ci    this.value = value;
264e41f4b71Sopenharmony_ci  }
265e41f4b71Sopenharmony_ci}
266e41f4b71Sopenharmony_ci
267e41f4b71Sopenharmony_ci@Entry
268e41f4b71Sopenharmony_ci@Component
269e41f4b71Sopenharmony_cistruct EntryComponent {
270e41f4b71Sopenharmony_ci  build() {
271e41f4b71Sopenharmony_ci    Column() {
272e41f4b71Sopenharmony_ci      // The parameters specified here will overwrite the default values defined locally during initial render. Not all parameters need to be initialized from the parent component.
273e41f4b71Sopenharmony_ci      MyComponent({ count: 1, increaseBy: 2 })
274e41f4b71Sopenharmony_ci        .width(300)
275e41f4b71Sopenharmony_ci      MyComponent({ title: new Model('Hello World 2'), count: 7 })
276e41f4b71Sopenharmony_ci    }
277e41f4b71Sopenharmony_ci  }
278e41f4b71Sopenharmony_ci}
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci@Component
281e41f4b71Sopenharmony_cistruct MyComponent {
282e41f4b71Sopenharmony_ci  @State title: Model = new Model('Hello World');
283e41f4b71Sopenharmony_ci  @State count: number = 0;
284e41f4b71Sopenharmony_ci  private increaseBy: number = 1;
285e41f4b71Sopenharmony_ci
286e41f4b71Sopenharmony_ci  build() {
287e41f4b71Sopenharmony_ci    Column() {
288e41f4b71Sopenharmony_ci      Text(`${this.title.value}`)
289e41f4b71Sopenharmony_ci        .margin(10)
290e41f4b71Sopenharmony_ci      Button(`Click to change title`)
291e41f4b71Sopenharmony_ci        .onClick(() => {
292e41f4b71Sopenharmony_ci          // The update of the @State decorated variable triggers the update of the <Text> component.
293e41f4b71Sopenharmony_ci          this.title.value = this.title.value === 'Hello ArkUI' ? 'Hello World' : 'Hello ArkUI';
294e41f4b71Sopenharmony_ci        })
295e41f4b71Sopenharmony_ci        .width(300)
296e41f4b71Sopenharmony_ci        .margin(10)
297e41f4b71Sopenharmony_ci
298e41f4b71Sopenharmony_ci      Button(`Click to increase count = ${this.count}`)
299e41f4b71Sopenharmony_ci        .onClick(() => {
300e41f4b71Sopenharmony_ci          // The update of the @State decorated variable triggers the update of the <Button> component.
301e41f4b71Sopenharmony_ci          this.count += this.increaseBy;
302e41f4b71Sopenharmony_ci        })
303e41f4b71Sopenharmony_ci        .width(300)
304e41f4b71Sopenharmony_ci        .margin(10)
305e41f4b71Sopenharmony_ci    }
306e41f4b71Sopenharmony_ci  }
307e41f4b71Sopenharmony_ci}
308e41f4b71Sopenharmony_ci```
309e41f4b71Sopenharmony_ci
310e41f4b71Sopenharmony_ci![Video-state](figures/Video-state.gif)
311e41f4b71Sopenharmony_ci
312e41f4b71Sopenharmony_ciFrom this example, we learn the initialization process of an \@State decorated variable on initial render.
313e41f4b71Sopenharmony_ci
314e41f4b71Sopenharmony_ci
315e41f4b71Sopenharmony_ci1. Apply the locally defined default value.
316e41f4b71Sopenharmony_ci
317e41f4b71Sopenharmony_ci   ```ts
318e41f4b71Sopenharmony_ci   @State title: Model = new Model('Hello World');
319e41f4b71Sopenharmony_ci   @State count: number = 0;
320e41f4b71Sopenharmony_ci   ```
321e41f4b71Sopenharmony_ci
322e41f4b71Sopenharmony_ci2. Apply the named parameter value, if one is provided.
323e41f4b71Sopenharmony_ci
324e41f4b71Sopenharmony_ci   ```ts
325e41f4b71Sopenharmony_ci   class C1 {
326e41f4b71Sopenharmony_ci      public count:number;
327e41f4b71Sopenharmony_ci      public increaseBy:number;
328e41f4b71Sopenharmony_ci      constructor(count: number, increaseBy:number) {
329e41f4b71Sopenharmony_ci        this.count = count;
330e41f4b71Sopenharmony_ci        this.increaseBy = increaseBy;
331e41f4b71Sopenharmony_ci     }
332e41f4b71Sopenharmony_ci   }
333e41f4b71Sopenharmony_ci   let obj = new C1(1, 2);
334e41f4b71Sopenharmony_ci   MyComponent(obj)
335e41f4b71Sopenharmony_ci   ```
336e41f4b71Sopenharmony_ci
337e41f4b71Sopenharmony_ci
338e41f4b71Sopenharmony_ci### Decorating Variables of the Map Type
339e41f4b71Sopenharmony_ci
340e41f4b71Sopenharmony_ci> **NOTE**
341e41f4b71Sopenharmony_ci>
342e41f4b71Sopenharmony_ci> Since API version 11, \@State supports the Map type.
343e41f4b71Sopenharmony_ci
344e41f4b71Sopenharmony_ciIn this example, the **message** variable is of the Map<number, string> type. When the button is clicked, the value of **message** changes, and the UI is re-rendered.
345e41f4b71Sopenharmony_ci
346e41f4b71Sopenharmony_ci```ts
347e41f4b71Sopenharmony_ci@Entry
348e41f4b71Sopenharmony_ci@Component
349e41f4b71Sopenharmony_cistruct MapSample {
350e41f4b71Sopenharmony_ci  @State message: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]);
351e41f4b71Sopenharmony_ci
352e41f4b71Sopenharmony_ci  build() {
353e41f4b71Sopenharmony_ci    Row() {
354e41f4b71Sopenharmony_ci      Column() {
355e41f4b71Sopenharmony_ci        ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
356e41f4b71Sopenharmony_ci          Text(`${item[0]}`).fontSize(30)
357e41f4b71Sopenharmony_ci          Text(`${item[1]}`).fontSize(30)
358e41f4b71Sopenharmony_ci          Divider()
359e41f4b71Sopenharmony_ci        })
360e41f4b71Sopenharmony_ci        Button('init map').onClick(() => {
361e41f4b71Sopenharmony_ci          this.message = new Map([[0, "a"], [1, "b"], [3, "c"]]);
362e41f4b71Sopenharmony_ci        })
363e41f4b71Sopenharmony_ci        Button('set new one').onClick(() => {
364e41f4b71Sopenharmony_ci          this.message.set(4, "d");
365e41f4b71Sopenharmony_ci        })
366e41f4b71Sopenharmony_ci        Button('clear').onClick(() => {
367e41f4b71Sopenharmony_ci          this.message.clear();
368e41f4b71Sopenharmony_ci        })
369e41f4b71Sopenharmony_ci        Button('replace the first one').onClick(() => {
370e41f4b71Sopenharmony_ci          this.message.set(0, "aa");
371e41f4b71Sopenharmony_ci        })
372e41f4b71Sopenharmony_ci        Button('delete the first one').onClick(() => {
373e41f4b71Sopenharmony_ci          this.message.delete(0);
374e41f4b71Sopenharmony_ci        })
375e41f4b71Sopenharmony_ci      }
376e41f4b71Sopenharmony_ci      .width('100%')
377e41f4b71Sopenharmony_ci    }
378e41f4b71Sopenharmony_ci    .height('100%')
379e41f4b71Sopenharmony_ci  }
380e41f4b71Sopenharmony_ci}
381e41f4b71Sopenharmony_ci```
382e41f4b71Sopenharmony_ci
383e41f4b71Sopenharmony_ci### Decorating Variables of the Set Type
384e41f4b71Sopenharmony_ci
385e41f4b71Sopenharmony_ci> **NOTE**
386e41f4b71Sopenharmony_ci>
387e41f4b71Sopenharmony_ci> Since API version 11, \@State supports the Set type.
388e41f4b71Sopenharmony_ci
389e41f4b71Sopenharmony_ciIn this example, the **message** variable is of the Set\<number\> type. When the button is clicked, the value of **message** changes, and the UI is re-rendered.
390e41f4b71Sopenharmony_ci
391e41f4b71Sopenharmony_ci```ts
392e41f4b71Sopenharmony_ci@Entry
393e41f4b71Sopenharmony_ci@Component
394e41f4b71Sopenharmony_cistruct SetSample {
395e41f4b71Sopenharmony_ci  @State message: Set<number> = new Set([0, 1, 2, 3, 4]);
396e41f4b71Sopenharmony_ci
397e41f4b71Sopenharmony_ci  build() {
398e41f4b71Sopenharmony_ci    Row() {
399e41f4b71Sopenharmony_ci      Column() {
400e41f4b71Sopenharmony_ci        ForEach(Array.from(this.message.entries()), (item: [number]) => {
401e41f4b71Sopenharmony_ci          Text(`${item[0]}`).fontSize(30)
402e41f4b71Sopenharmony_ci          Divider()
403e41f4b71Sopenharmony_ci        })
404e41f4b71Sopenharmony_ci        Button('init set').onClick(() => {
405e41f4b71Sopenharmony_ci          this.message = new Set([0, 1, 2, 3, 4]);
406e41f4b71Sopenharmony_ci        })
407e41f4b71Sopenharmony_ci        Button('set new one').onClick(() => {
408e41f4b71Sopenharmony_ci          this.message.add(5);
409e41f4b71Sopenharmony_ci        })
410e41f4b71Sopenharmony_ci        Button('clear').onClick(() => {
411e41f4b71Sopenharmony_ci          this.message.clear();
412e41f4b71Sopenharmony_ci        })
413e41f4b71Sopenharmony_ci        Button('delete the first one').onClick(() => {
414e41f4b71Sopenharmony_ci          this.message.delete(0);
415e41f4b71Sopenharmony_ci        })
416e41f4b71Sopenharmony_ci      }
417e41f4b71Sopenharmony_ci      .width('100%')
418e41f4b71Sopenharmony_ci    }
419e41f4b71Sopenharmony_ci    .height('100%')
420e41f4b71Sopenharmony_ci  }
421e41f4b71Sopenharmony_ci}
422e41f4b71Sopenharmony_ci```
423e41f4b71Sopenharmony_ci
424e41f4b71Sopenharmony_ci## Union Type
425e41f4b71Sopenharmony_ci
426e41f4b71Sopenharmony_ci@State supports **undefined**, **null**, and union types. In the following example, the type of **count** is number | undefined. If the property or type of **count** is changed when the button is clicked, the change will be synced to the view.
427e41f4b71Sopenharmony_ci
428e41f4b71Sopenharmony_ci```ts
429e41f4b71Sopenharmony_ci@Entry
430e41f4b71Sopenharmony_ci@Component
431e41f4b71Sopenharmony_cistruct EntryComponent {
432e41f4b71Sopenharmony_ci  build() {
433e41f4b71Sopenharmony_ci    Column() {
434e41f4b71Sopenharmony_ci      MyComponent()
435e41f4b71Sopenharmony_ci    }
436e41f4b71Sopenharmony_ci  }
437e41f4b71Sopenharmony_ci}
438e41f4b71Sopenharmony_ci
439e41f4b71Sopenharmony_ci@Component
440e41f4b71Sopenharmony_cistruct MyComponent {
441e41f4b71Sopenharmony_ci  @State count: number | undefined = 0;
442e41f4b71Sopenharmony_ci
443e41f4b71Sopenharmony_ci  build() {
444e41f4b71Sopenharmony_ci    Column() {
445e41f4b71Sopenharmony_ci      Text(`count(${this.count})`)
446e41f4b71Sopenharmony_ci      Button('change')
447e41f4b71Sopenharmony_ci        .onClick(() => {
448e41f4b71Sopenharmony_ci          this.count = undefined;
449e41f4b71Sopenharmony_ci        })
450e41f4b71Sopenharmony_ci    }
451e41f4b71Sopenharmony_ci  }
452e41f4b71Sopenharmony_ci}
453e41f4b71Sopenharmony_ci```
454e41f4b71Sopenharmony_ci
455e41f4b71Sopenharmony_ci
456e41f4b71Sopenharmony_ci## FAQs
457e41f4b71Sopenharmony_ci
458e41f4b71Sopenharmony_ci### Failure to Change a State Variable Using an Arrow Function
459e41f4b71Sopenharmony_ci
460e41f4b71Sopenharmony_ciThe **this** object inside the arrow function's body is established based on the scope where the arrow function is defined points, not the scope where the arrow function is executed. As such, **this** of **changeCoverUrl** points to **PlayDetailViewModel** instead of the state variable decorated by @State.
461e41f4b71Sopenharmony_ci
462e41f4b71Sopenharmony_ciIncorrect usage:
463e41f4b71Sopenharmony_ci
464e41f4b71Sopenharmony_ci```ts
465e41f4b71Sopenharmony_ci
466e41f4b71Sopenharmony_ciexport default class PlayDetailViewModel {
467e41f4b71Sopenharmony_ci  coverUrl: string = '#00ff00'
468e41f4b71Sopenharmony_ci
469e41f4b71Sopenharmony_ci  changeCoverUrl= ()=> {
470e41f4b71Sopenharmony_ci    this.coverUrl = '#00F5FF';
471e41f4b71Sopenharmony_ci  }
472e41f4b71Sopenharmony_ci
473e41f4b71Sopenharmony_ci}
474e41f4b71Sopenharmony_ci```
475e41f4b71Sopenharmony_ci
476e41f4b71Sopenharmony_ci```ts
477e41f4b71Sopenharmony_ciimport PlayDetailViewModel from './PlayDetailViewModel'
478e41f4b71Sopenharmony_ci
479e41f4b71Sopenharmony_ci@Entry
480e41f4b71Sopenharmony_ci@Component
481e41f4b71Sopenharmony_cistruct PlayDetailPage {
482e41f4b71Sopenharmony_ci  @State vm: PlayDetailViewModel = new PlayDetailViewModel();
483e41f4b71Sopenharmony_ci
484e41f4b71Sopenharmony_ci  build() {
485e41f4b71Sopenharmony_ci    Stack() {
486e41f4b71Sopenharmony_ci      Text(this.vm.coverUrl).width(100).height(100).backgroundColor(this.vm.coverUrl)
487e41f4b71Sopenharmony_ci      Row() {
488e41f4b71Sopenharmony_ci        Button ('Change Color')
489e41f4b71Sopenharmony_ci          .onClick(() => {
490e41f4b71Sopenharmony_ci            this.vm.changeCoverUrl();
491e41f4b71Sopenharmony_ci          })
492e41f4b71Sopenharmony_ci      }
493e41f4b71Sopenharmony_ci    }
494e41f4b71Sopenharmony_ci    .width('100%')
495e41f4b71Sopenharmony_ci    .height('100%')
496e41f4b71Sopenharmony_ci    .alignContent(Alignment.Top)
497e41f4b71Sopenharmony_ci  }
498e41f4b71Sopenharmony_ci}
499e41f4b71Sopenharmony_ci```
500e41f4b71Sopenharmony_ci
501e41f4b71Sopenharmony_ciTo fix the issue, pass **this.vm** and call the attribute of the decorated state variable to assign a value.
502e41f4b71Sopenharmony_ci
503e41f4b71Sopenharmony_ciExample:
504e41f4b71Sopenharmony_ci
505e41f4b71Sopenharmony_ci```ts
506e41f4b71Sopenharmony_ci
507e41f4b71Sopenharmony_ciexport default class PlayDetailViewModel {
508e41f4b71Sopenharmony_ci  coverUrl: string = '#00ff00'
509e41f4b71Sopenharmony_ci
510e41f4b71Sopenharmony_ci  changeCoverUrl= (model:PlayDetailViewModel)=> {
511e41f4b71Sopenharmony_ci    model.coverUrl = '#00F5FF'
512e41f4b71Sopenharmony_ci  }
513e41f4b71Sopenharmony_ci
514e41f4b71Sopenharmony_ci}
515e41f4b71Sopenharmony_ci```
516e41f4b71Sopenharmony_ci
517e41f4b71Sopenharmony_ci```ts
518e41f4b71Sopenharmony_ciimport PlayDetailViewModel from './PlayDetailViewModel'
519e41f4b71Sopenharmony_ci
520e41f4b71Sopenharmony_ci@Entry
521e41f4b71Sopenharmony_ci@Component
522e41f4b71Sopenharmony_cistruct PlayDetailPage {
523e41f4b71Sopenharmony_ci  @State vm: PlayDetailViewModel = new PlayDetailViewModel();
524e41f4b71Sopenharmony_ci
525e41f4b71Sopenharmony_ci  build() {
526e41f4b71Sopenharmony_ci    Stack() {
527e41f4b71Sopenharmony_ci      Text(this.vm.coverUrl).width(100).height(100).backgroundColor(this.vm.coverUrl)
528e41f4b71Sopenharmony_ci      Row() {
529e41f4b71Sopenharmony_ci        Button ('Change Color')
530e41f4b71Sopenharmony_ci          .onClick(() => {
531e41f4b71Sopenharmony_ci            let self = this.vm;
532e41f4b71Sopenharmony_ci            this.vm.changeCoverUrl(self);
533e41f4b71Sopenharmony_ci          })
534e41f4b71Sopenharmony_ci      }
535e41f4b71Sopenharmony_ci    }
536e41f4b71Sopenharmony_ci    .width('100%')
537e41f4b71Sopenharmony_ci    .height('100%')
538e41f4b71Sopenharmony_ci    .alignContent(Alignment.Top)
539e41f4b71Sopenharmony_ci  }
540e41f4b71Sopenharmony_ci}
541e41f4b71Sopenharmony_ci```
542e41f4b71Sopenharmony_ci
543e41f4b71Sopenharmony_ci### State Variable Changes in the Constructor Not Taking Effect
544e41f4b71Sopenharmony_ci
545e41f4b71Sopenharmony_ciIn state management, classes are wrapped with a proxy. When a member variable of a class is changed in a component, the proxy intercepts the change. When the value in the data source is changed, the proxy notifies the bound component of the change. In this way, the change can be observed and trigger UI re-rendering.
546e41f4b71Sopenharmony_ci
547e41f4b71Sopenharmony_ciIf you initialize the arrow function for modifying **success** in the constructor, **this** points to the original **TestModel** class, which has not been wrapped with a proxy. As a result, the change can be observed through query event triggering.
548e41f4b71Sopenharmony_ci
549e41f4b71Sopenharmony_ciTo enable the change to be observable, place the arrow function for modifying **success** in **query**. As **query** is wrapped with a proxy and has an object initialized, **this** points to the proxy object.
550e41f4b71Sopenharmony_ci
551e41f4b71Sopenharmony_ci[Incorrect Usage]
552e41f4b71Sopenharmony_ci
553e41f4b71Sopenharmony_ci```ts
554e41f4b71Sopenharmony_ci@Entry
555e41f4b71Sopenharmony_ci@Component
556e41f4b71Sopenharmony_cistruct Index {
557e41f4b71Sopenharmony_ci  @State viewModel: TestModel = new TestModel();
558e41f4b71Sopenharmony_ci
559e41f4b71Sopenharmony_ci  build() {
560e41f4b71Sopenharmony_ci    Row() {
561e41f4b71Sopenharmony_ci      Column() {
562e41f4b71Sopenharmony_ci        Text(this.viewModel.isSuccess ? 'success' : 'failed')
563e41f4b71Sopenharmony_ci          .fontSize(50)
564e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
565e41f4b71Sopenharmony_ci          .onClick(() => {
566e41f4b71Sopenharmony_ci            this.viewModel.query();
567e41f4b71Sopenharmony_ci          })
568e41f4b71Sopenharmony_ci      }.width('100%')
569e41f4b71Sopenharmony_ci    }.height('100%')
570e41f4b71Sopenharmony_ci  }
571e41f4b71Sopenharmony_ci}
572e41f4b71Sopenharmony_ci
573e41f4b71Sopenharmony_ciexport class TestModel {
574e41f4b71Sopenharmony_ci  isSuccess: boolean = false;
575e41f4b71Sopenharmony_ci  model: Model
576e41f4b71Sopenharmony_ci
577e41f4b71Sopenharmony_ci  constructor() {
578e41f4b71Sopenharmony_ci    this.model = new Model(() => {
579e41f4b71Sopenharmony_ci      this.isSuccess = true;
580e41f4b71Sopenharmony_ci      console.log(`this.isSuccess: ${this.isSuccess}`);
581e41f4b71Sopenharmony_ci    })
582e41f4b71Sopenharmony_ci  }
583e41f4b71Sopenharmony_ci
584e41f4b71Sopenharmony_ci  query() {
585e41f4b71Sopenharmony_ci    this.model.query();
586e41f4b71Sopenharmony_ci  }
587e41f4b71Sopenharmony_ci}
588e41f4b71Sopenharmony_ci
589e41f4b71Sopenharmony_ciexport class Model {
590e41f4b71Sopenharmony_ci  callback: () => void
591e41f4b71Sopenharmony_ci
592e41f4b71Sopenharmony_ci  constructor(cb: () => void) {
593e41f4b71Sopenharmony_ci    this.callback = cb;
594e41f4b71Sopenharmony_ci  }
595e41f4b71Sopenharmony_ci
596e41f4b71Sopenharmony_ci  query() {
597e41f4b71Sopenharmony_ci    this.callback();
598e41f4b71Sopenharmony_ci  }
599e41f4b71Sopenharmony_ci}
600e41f4b71Sopenharmony_ci```
601e41f4b71Sopenharmony_ci
602e41f4b71Sopenharmony_ciIn the preceding example, the state variable is changed in the constructor. After the button is clicked, the change takes effect, indicated by "this.isSuccess: true" in the log. However, the page is not refreshed, and still displays "failed".
603e41f4b71Sopenharmony_ci
604e41f4b71Sopenharmony_ci[Example]
605e41f4b71Sopenharmony_ci
606e41f4b71Sopenharmony_ci```ts
607e41f4b71Sopenharmony_ci@Entry
608e41f4b71Sopenharmony_ci@Component
609e41f4b71Sopenharmony_cistruct Index {
610e41f4b71Sopenharmony_ci  @State viewModel: TestModel = new TestModel();
611e41f4b71Sopenharmony_ci
612e41f4b71Sopenharmony_ci  build() {
613e41f4b71Sopenharmony_ci    Row() {
614e41f4b71Sopenharmony_ci      Column() {
615e41f4b71Sopenharmony_ci        Text(this.viewModel.isSuccess ? 'success' : 'failed')
616e41f4b71Sopenharmony_ci          .fontSize(50)
617e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
618e41f4b71Sopenharmony_ci          .onClick(() => {
619e41f4b71Sopenharmony_ci            this.viewModel.query();
620e41f4b71Sopenharmony_ci          })
621e41f4b71Sopenharmony_ci      }.width('100%')
622e41f4b71Sopenharmony_ci    }.height('100%')
623e41f4b71Sopenharmony_ci  }
624e41f4b71Sopenharmony_ci}
625e41f4b71Sopenharmony_ci
626e41f4b71Sopenharmony_ciexport class TestModel {
627e41f4b71Sopenharmony_ci  isSuccess: boolean = false;
628e41f4b71Sopenharmony_ci  model: Model = new Model(() => {
629e41f4b71Sopenharmony_ci  })
630e41f4b71Sopenharmony_ci
631e41f4b71Sopenharmony_ci  query() {
632e41f4b71Sopenharmony_ci    this.model.callback = () => {
633e41f4b71Sopenharmony_ci      this.isSuccess = true;
634e41f4b71Sopenharmony_ci    }
635e41f4b71Sopenharmony_ci    this.model.query();
636e41f4b71Sopenharmony_ci  }
637e41f4b71Sopenharmony_ci}
638e41f4b71Sopenharmony_ci
639e41f4b71Sopenharmony_ciexport class Model {
640e41f4b71Sopenharmony_ci  callback: () => void
641e41f4b71Sopenharmony_ci
642e41f4b71Sopenharmony_ci  constructor(cb: () => void) {
643e41f4b71Sopenharmony_ci    this.callback = cb;
644e41f4b71Sopenharmony_ci  }
645e41f4b71Sopenharmony_ci
646e41f4b71Sopenharmony_ci  query() {
647e41f4b71Sopenharmony_ci    this.callback();
648e41f4b71Sopenharmony_ci  }
649e41f4b71Sopenharmony_ci}
650e41f4b71Sopenharmony_ci```
651e41f4b71Sopenharmony_ci
652e41f4b71Sopenharmony_ciIn the preceding example, the state variable is changed through a method of the class. After the button is clicked, the page content changes from "failed" to "success."
653e41f4b71Sopenharmony_ci
654e41f4b71Sopenharmony_ci### A state variable causes a re-render of merely the bound UI component.
655e41f4b71Sopenharmony_ci
656e41f4b71Sopenharmony_ciExample 1
657e41f4b71Sopenharmony_ci
658e41f4b71Sopenharmony_ci```ts
659e41f4b71Sopenharmony_ciclass Parent {
660e41f4b71Sopenharmony_ci  son: string = '000';
661e41f4b71Sopenharmony_ci}
662e41f4b71Sopenharmony_ci
663e41f4b71Sopenharmony_ci@Entry
664e41f4b71Sopenharmony_ci@Component
665e41f4b71Sopenharmony_cistruct Test {
666e41f4b71Sopenharmony_ci  @State son: string = '111';
667e41f4b71Sopenharmony_ci  @State parent: Parent = new Parent();
668e41f4b71Sopenharmony_ci
669e41f4b71Sopenharmony_ci  aboutToAppear(): void {
670e41f4b71Sopenharmony_ci    this.parent.son = this.son;
671e41f4b71Sopenharmony_ci  }
672e41f4b71Sopenharmony_ci
673e41f4b71Sopenharmony_ci  build() {
674e41f4b71Sopenharmony_ci    Column() {
675e41f4b71Sopenharmony_ci      Text(`${this.son}`);
676e41f4b71Sopenharmony_ci      Text(`${this.parent.son}`);
677e41f4b71Sopenharmony_ci      Button('change')
678e41f4b71Sopenharmony_ci        .onClick(() => {
679e41f4b71Sopenharmony_ci          this.parent.son = '222';
680e41f4b71Sopenharmony_ci        })
681e41f4b71Sopenharmony_ci    }
682e41f4b71Sopenharmony_ci  }
683e41f4b71Sopenharmony_ci}
684e41f4b71Sopenharmony_ci```
685e41f4b71Sopenharmony_ci
686e41f4b71Sopenharmony_ciIn the preceding example, clicking **Button('change')** changes the second-line text from **'111'** to **'222'**, but does not change the first-line text. This is because **son** is of the primitive string type, for which a shallow copy is performed. In shallow copy, clicking the button changes the value of **son** in **parent**, but the value of **this.son** remains unchanged.
687e41f4b71Sopenharmony_ci
688e41f4b71Sopenharmony_ciExample 2
689e41f4b71Sopenharmony_ci
690e41f4b71Sopenharmony_ci```ts
691e41f4b71Sopenharmony_ciclass Son {
692e41f4b71Sopenharmony_ci  son: string = '000';
693e41f4b71Sopenharmony_ci
694e41f4b71Sopenharmony_ci  constructor(son: string) {
695e41f4b71Sopenharmony_ci    this.son = son;
696e41f4b71Sopenharmony_ci  }
697e41f4b71Sopenharmony_ci}
698e41f4b71Sopenharmony_ci
699e41f4b71Sopenharmony_ciclass Parent {
700e41f4b71Sopenharmony_ci  son: Son = new Son('111');
701e41f4b71Sopenharmony_ci}
702e41f4b71Sopenharmony_ci
703e41f4b71Sopenharmony_ci@Entry
704e41f4b71Sopenharmony_ci@Component
705e41f4b71Sopenharmony_cistruct Test {
706e41f4b71Sopenharmony_ci  @State son: Son = new Son('222');
707e41f4b71Sopenharmony_ci  @State parent: Parent = new Parent();
708e41f4b71Sopenharmony_ci
709e41f4b71Sopenharmony_ci  aboutToAppear(): void {
710e41f4b71Sopenharmony_ci    this.parent.son = this.son;
711e41f4b71Sopenharmony_ci  }
712e41f4b71Sopenharmony_ci
713e41f4b71Sopenharmony_ci  build() {
714e41f4b71Sopenharmony_ci    Column() {
715e41f4b71Sopenharmony_ci      Text(`${this.son.son}`);
716e41f4b71Sopenharmony_ci      Text(`${this.parent.son.son}`);
717e41f4b71Sopenharmony_ci      Button('change')
718e41f4b71Sopenharmony_ci        .onClick(() => {
719e41f4b71Sopenharmony_ci          this.parent.son.son = '333';
720e41f4b71Sopenharmony_ci        })
721e41f4b71Sopenharmony_ci    }
722e41f4b71Sopenharmony_ci  }
723e41f4b71Sopenharmony_ci}
724e41f4b71Sopenharmony_ci```
725e41f4b71Sopenharmony_ci
726e41f4b71Sopenharmony_ciIn the preceding example, a reference of **son** is assigned to the **son** property of **parent** in **aboutToAppear**. In this case, if you click the button to change the property in **son**, the first **Text** component is re-rendered, but not the second **Text** component, which is unable to observe changes at the second layer.
727e41f4b71Sopenharmony_ci
728e41f4b71Sopenharmony_ciExample 3
729e41f4b71Sopenharmony_ci
730e41f4b71Sopenharmony_ci```ts
731e41f4b71Sopenharmony_ciclass Son {
732e41f4b71Sopenharmony_ci  son: string = '000';
733e41f4b71Sopenharmony_ci
734e41f4b71Sopenharmony_ci  constructor(son: string) {
735e41f4b71Sopenharmony_ci    this.son = son;
736e41f4b71Sopenharmony_ci  }
737e41f4b71Sopenharmony_ci}
738e41f4b71Sopenharmony_ci
739e41f4b71Sopenharmony_ciclass Parent {
740e41f4b71Sopenharmony_ci  son: Son = new Son('111');
741e41f4b71Sopenharmony_ci}
742e41f4b71Sopenharmony_ci
743e41f4b71Sopenharmony_ci@Entry
744e41f4b71Sopenharmony_ci@Component
745e41f4b71Sopenharmony_cistruct Test {
746e41f4b71Sopenharmony_ci  @State son: Son = new Son('222');
747e41f4b71Sopenharmony_ci  @State parent: Parent = new Parent();
748e41f4b71Sopenharmony_ci
749e41f4b71Sopenharmony_ci  aboutToAppear(): void {
750e41f4b71Sopenharmony_ci    this.parent.son = this.son;
751e41f4b71Sopenharmony_ci  }
752e41f4b71Sopenharmony_ci
753e41f4b71Sopenharmony_ci  build() {
754e41f4b71Sopenharmony_ci    Column() {
755e41f4b71Sopenharmony_ci      Text(`${this.son.son}`);
756e41f4b71Sopenharmony_ci      Text(`${this.parent.son.son}`);
757e41f4b71Sopenharmony_ci      Button('change')
758e41f4b71Sopenharmony_ci        .onClick(() => {
759e41f4b71Sopenharmony_ci          this.parent.son = new Son('444');
760e41f4b71Sopenharmony_ci          this.parent.son.son = '333';
761e41f4b71Sopenharmony_ci        })
762e41f4b71Sopenharmony_ci    }
763e41f4b71Sopenharmony_ci  }
764e41f4b71Sopenharmony_ci}
765e41f4b71Sopenharmony_ci```
766e41f4b71Sopenharmony_ci
767e41f4b71Sopenharmony_ciIn the preceding example, clicking **Button('change')** changes the second-line text from **'222'** to **'333'**, but does not change the first-line text. This is because **this.parent.son = new Son('444')'** is executed after the button is clicked, which means that a **Son** object is created, and then **this.parent.son.son = '333'** is executed. As a result, clicking the button changes the value of **son** in the new **Son** object, and the one in the original Son object is not affected.
768e41f4b71Sopenharmony_ci
769e41f4b71Sopenharmony_ci### Repeated Value Changes to State Variables by Complex Constants Trigger Re-rendering
770e41f4b71Sopenharmony_ci
771e41f4b71Sopenharmony_ci```ts
772e41f4b71Sopenharmony_ciclass DataObj {
773e41f4b71Sopenharmony_ci  name: string = 'default name';
774e41f4b71Sopenharmony_ci
775e41f4b71Sopenharmony_ci  constructor(name: string) {
776e41f4b71Sopenharmony_ci    this.name = name;
777e41f4b71Sopenharmony_ci  }
778e41f4b71Sopenharmony_ci}
779e41f4b71Sopenharmony_ci
780e41f4b71Sopenharmony_ci@Entry
781e41f4b71Sopenharmony_ci@Component
782e41f4b71Sopenharmony_cistruct Index {
783e41f4b71Sopenharmony_ci  list: DataObj[] = [new DataObj('a'), new DataObj('b'), new DataObj('c')];
784e41f4b71Sopenharmony_ci  @State dataObjFromList: DataObj = this.list[0];
785e41f4b71Sopenharmony_ci
786e41f4b71Sopenharmony_ci  build() {
787e41f4b71Sopenharmony_ci    Column() {
788e41f4b71Sopenharmony_ci      ConsumerChild({ dataObj: this.dataObjFromList })
789e41f4b71Sopenharmony_ci      Button('change to self').onClick(() => {
790e41f4b71Sopenharmony_ci        this.dataObjFromList = this.list[0];
791e41f4b71Sopenharmony_ci      })
792e41f4b71Sopenharmony_ci    }
793e41f4b71Sopenharmony_ci  }
794e41f4b71Sopenharmony_ci}
795e41f4b71Sopenharmony_ci
796e41f4b71Sopenharmony_ci@Component
797e41f4b71Sopenharmony_cistruct ConsumerChild {
798e41f4b71Sopenharmony_ci  @Link @Watch('onDataObjChange') dataObj: DataObj;
799e41f4b71Sopenharmony_ci
800e41f4b71Sopenharmony_ci  onDataObjChange() {
801e41f4b71Sopenharmony_ci    console.log("dataObj changed");
802e41f4b71Sopenharmony_ci  }
803e41f4b71Sopenharmony_ci
804e41f4b71Sopenharmony_ci  build() {
805e41f4b71Sopenharmony_ci    Column() {
806e41f4b71Sopenharmony_ci      Text(this.dataObj.name).fontSize(30)
807e41f4b71Sopenharmony_ci    }
808e41f4b71Sopenharmony_ci  }
809e41f4b71Sopenharmony_ci}
810e41f4b71Sopenharmony_ci```
811e41f4b71Sopenharmony_ci
812e41f4b71Sopenharmony_ciIn the preceding example, each time you click Button('change to self'), the same class constant is assigned to a state variable of the **Class** type, triggering re-rendering. In state management V1, a proxy is added to the class objects decorated by @Observed and the Class, Date, Map, Set, and Array decorated by @State to observe the changes of top-level attributes or API invoking. 
813e41f4b71Sopenharmony_ci**dataObjFromList** is of a **Proxy** type but **list[0]** is of an **Object** type. As a result, when **list[0]** is assigned to **dataObjFromList**, the value changes trigger re-rendering. 
814e41f4b71Sopenharmony_ciTo avoid unnecessary value changes and re-renders, use @Observed to decorate the class, or use [UIUtils.getTarget()](./arkts-new-getTarget.md) to obtain the original value and determine whether the original and new values are the same. If they are the same, do not perform value changes. 
815e41f4b71Sopenharmony_ciMethod 1: Add @Observed decorator.
816e41f4b71Sopenharmony_ci
817e41f4b71Sopenharmony_ci```ts
818e41f4b71Sopenharmony_ci@Observed
819e41f4b71Sopenharmony_ciclass DataObj {
820e41f4b71Sopenharmony_ci  name: string = 'default name';
821e41f4b71Sopenharmony_ci
822e41f4b71Sopenharmony_ci  constructor(name: string) {
823e41f4b71Sopenharmony_ci    this.name = name;
824e41f4b71Sopenharmony_ci  }
825e41f4b71Sopenharmony_ci}
826e41f4b71Sopenharmony_ci
827e41f4b71Sopenharmony_ci@Entry
828e41f4b71Sopenharmony_ci@Component
829e41f4b71Sopenharmony_cistruct Index {
830e41f4b71Sopenharmony_ci  list: DataObj[] = [new DataObj('a'), new DataObj('b'), new DataObj('c')];
831e41f4b71Sopenharmony_ci  @State dataObjFromList: DataObj = this.list[0];
832e41f4b71Sopenharmony_ci
833e41f4b71Sopenharmony_ci  build() {
834e41f4b71Sopenharmony_ci    Column() {
835e41f4b71Sopenharmony_ci      ConsumerChild({ dataObj: this.dataObjFromList })
836e41f4b71Sopenharmony_ci      Button('change to self').onClick(() => {
837e41f4b71Sopenharmony_ci        this.dataObjFromList = this.list[0];
838e41f4b71Sopenharmony_ci      })
839e41f4b71Sopenharmony_ci    }
840e41f4b71Sopenharmony_ci  }
841e41f4b71Sopenharmony_ci}
842e41f4b71Sopenharmony_ci
843e41f4b71Sopenharmony_ci@Component
844e41f4b71Sopenharmony_cistruct ConsumerChild {
845e41f4b71Sopenharmony_ci  @Link @Watch('onDataObjChange') dataObj: DataObj;
846e41f4b71Sopenharmony_ci
847e41f4b71Sopenharmony_ci  onDataObjChange() {
848e41f4b71Sopenharmony_ci    console.log("dataObj changed");
849e41f4b71Sopenharmony_ci  }
850e41f4b71Sopenharmony_ci
851e41f4b71Sopenharmony_ci  build() {
852e41f4b71Sopenharmony_ci    Column() {
853e41f4b71Sopenharmony_ci      Text(this.dataObj.name).fontSize(30)
854e41f4b71Sopenharmony_ci    }
855e41f4b71Sopenharmony_ci  }
856e41f4b71Sopenharmony_ci}
857e41f4b71Sopenharmony_ci```
858e41f4b71Sopenharmony_ci
859e41f4b71Sopenharmony_ciIn the preceding example, the @Observed decorator is added to decorate the class, **list[0]** is of the **Proxy** type. In this case, when reassign a value, the same object will not be re-rendered.
860e41f4b71Sopenharmony_ci
861e41f4b71Sopenharmony_ciMethod 2: Use [UIUtils.getTarget()](./arkts-new-getTarget.md) to obtain the original object.
862e41f4b71Sopenharmony_ci
863e41f4b71Sopenharmony_ci```ts
864e41f4b71Sopenharmony_ciimport { UIUtils } from '@ohos.arkui.StateManagement';
865e41f4b71Sopenharmony_ci
866e41f4b71Sopenharmony_ciclass DataObj {
867e41f4b71Sopenharmony_ci  name: string = 'default name';
868e41f4b71Sopenharmony_ci
869e41f4b71Sopenharmony_ci  constructor(name: string) {
870e41f4b71Sopenharmony_ci    this.name = name;
871e41f4b71Sopenharmony_ci  }
872e41f4b71Sopenharmony_ci}
873e41f4b71Sopenharmony_ci
874e41f4b71Sopenharmony_ci@Entry
875e41f4b71Sopenharmony_ci@Component
876e41f4b71Sopenharmony_cistruct Index {
877e41f4b71Sopenharmony_ci  list: DataObj[] = [new DataObj('a'), new DataObj('b'), new DataObj('c')];
878e41f4b71Sopenharmony_ci  @State dataObjFromList: DataObj = this.list[0];
879e41f4b71Sopenharmony_ci
880e41f4b71Sopenharmony_ci  build() {
881e41f4b71Sopenharmony_ci    Column() {
882e41f4b71Sopenharmony_ci      ConsumerChild({ dataObj: this.dataObjFromList })
883e41f4b71Sopenharmony_ci      Button('change to self').onClick(() => {
884e41f4b71Sopenharmony_ci        // Obtain the original value and compare it with the new value.
885e41f4b71Sopenharmony_ci        if (UIUtils.getTarget(this.dataObjFromList) !== this.list[0]) {
886e41f4b71Sopenharmony_ci          this.dataObjFromList = this.list[0];
887e41f4b71Sopenharmony_ci        }
888e41f4b71Sopenharmony_ci      })
889e41f4b71Sopenharmony_ci    }
890e41f4b71Sopenharmony_ci  }
891e41f4b71Sopenharmony_ci}
892e41f4b71Sopenharmony_ci
893e41f4b71Sopenharmony_ci@Component
894e41f4b71Sopenharmony_cistruct ConsumerChild {
895e41f4b71Sopenharmony_ci  @Link @Watch('onDataObjChange') dataObj: DataObj;
896e41f4b71Sopenharmony_ci
897e41f4b71Sopenharmony_ci  onDataObjChange() {
898e41f4b71Sopenharmony_ci    console.log("dataObj changed");
899e41f4b71Sopenharmony_ci  }
900e41f4b71Sopenharmony_ci
901e41f4b71Sopenharmony_ci  build() {
902e41f4b71Sopenharmony_ci    Column() {
903e41f4b71Sopenharmony_ci      Text(this.dataObj.name).fontSize(30)
904e41f4b71Sopenharmony_ci    }
905e41f4b71Sopenharmony_ci  }
906e41f4b71Sopenharmony_ci}
907e41f4b71Sopenharmony_ci```
908e41f4b71Sopenharmony_ci
909e41f4b71Sopenharmony_ciIn the preceding example, **getTarget** is used to obtain the original value of the corresponding state variable before value change. After comparison, if the original value is the same as the new value, re-rendering will not be triggered.
910