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 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 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