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