1# \@Provide and \@Consume Decorators: Two-Way Synchronization with Descendant Components 2 3 4\@Provide and \@Consume are used for two-way data synchronization with descendant components when state data needs to be transferred between multiple levels. They do not involve passing a variable from component to component multiple times. 5 6 7An \@Provide decorated state variable exists in the ancestor component and is said to be "provided" to descendent components. An \@Consume decorated state variable is used in a descendent component. It is linked to ("consumes") the provided state variable in its ancestor component. 8 9 10> **NOTE** 11> 12> These two decorators can be used in ArkTS widgets since API version 9. 13> 14> These two decorators can be used in atomic services since API version 11. 15 16## Overview 17 18\@Provide/\@Consume decorated state variables have the following features: 19 20- An \@Provide decorated state variable becomes available to all descendent components of the providing component automatically. The variable is said to be "provided" to other components. This means that you do not need to pass a variable from component to component multiple times. 21 22- A descendent component gains access to the provided state variable by decorating a variable with \@Consume. This establishes a two-way data synchronization between the provided and the consumed variable. This synchronization works in the same manner as a combination of \@State and \@Link does. The only difference is that the former allows transfer across multiple levels of the UI parent-child hierarchy. 23 24- \@Provide and \@Consume can be bound using the same variable name or variable alias. Whenever possible, use the same variable types to prevent implicit type conversion and consequently application behavior exceptions. 25 26 27```ts 28// Binding through the same variable name 29@Provide a: number = 0; 30@Consume a: number; 31 32// Binding through the same variable alias 33@Provide('a') b: number = 0; 34@Consume('a') c: number; 35``` 36 37 38When \@Provide and \@Consume are bound through the same variable name or variable alias, the variables decorated by \@Provide and \@Consume are in a one-to-many relationship. A custom component, including its child components, should not contain multiple \@Provide decorated variables under the same name or alias. Otherwise, a runtime error will occur. 39 40 41## Decorator Description 42 43The rules of \@State also apply to \@Provide. The difference is that \@Provide also functions as a synchronization source for multi-layer descendants. 44 45| \@Provide Decorator| Description | 46| -------------- | ---------------------------------------- | 47| Decorator parameters | Alias: constant string, optional.<br>If the alias is specified, the variable is provided under the alias name only. If the alias is not specified, the variable is provided under the variable name.| 48| Synchronization type | Two-way:<br>from the \@Provide decorated variable to all \@Consume decorated variables; and the other way around. The two-way synchronization behaviour is the same as that of the combination of \@State and \@Link.| 49| 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 and Set types.<br>The union types defined by the ArkUI framework, including Length, ResourceStr, and ResourceColor, are supported.<br>The type must be specified.<br>The type of the provided and the consumed variables must be the same.<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 and later versions) Union type of the preceding types, for example, string \| number, string \| undefined or ClassA \| null. For details, see [Support for Union Type](#support-for-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, **@Provide a: string \**| **undefined = undefined** is recommended; **@Provide a: string = undefined** is not recommended. 50| Initial value for the decorated variable | Mandatory. | 51| Support for the **allowOverride** parameter | Yes. After **allowOverride** is declared, both aliases and attribute names can be overridden. For details, see [Support for the allowOverride Parameter](#support-for-the-allowoverride-parameter).| 52 53| \@Consume Decorator| Description | 54| -------------- | ---------------------------------------- | 55| Decorator parameters | Alias: constant string, optional.<br>If the alias is specified, the alias name is used for matching with the \@Provide decorated variable. Otherwise, the variable name is used.| 56| Synchronization type | Two-way: from the \@Provide decorated variable to all \@Consume decorated variables; and the other way around. The two-way synchronization behaviour is the same as that of the combination of \@State and \@Link.| 57| Allowed variable types | Object, class, string, number, Boolean, enum, and array of these types.<br>Date type.<br>The union types defined by the ArkUI framework, including Length, ResourceStr, and ResourceColor, are supported. The type must be specified.<br>The type of the provided and the consumed variables must be the same.<br>An \@Consume decorated variable must have a matching \@Provide decorated variable with the corresponding attribute and alias on its parent or ancestor component.<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 and later versions) Union type of the preceding types, for example, string \| number, string \| undefined or ClassA \| null. For details, see [Support for Union Type](#support-for-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, @Consume a: string \| undefined. 58| Initial value for the decorated variable | Initialization of the decorated variables is forbidden. | 59 60 61## Variable Transfer/Access Rules 62 63 64| \@Provide Transfer/Access| Description | 65| -------------- | ---------------------------------------- | 66| Initialization and update from the parent component | Optional. An @Provide decorated variable can be initialized from a regular variable (whose change does not trigger UI refresh) or an [\@State](./arkts-state.md), [\@Link](./arkts-link.md), [\@Prop](./arkts-prop.md), \@Provide, \@Consume, [\@ObjectLink](./arkts-observed-and-objectlink.md), [\@StorageLink](./arkts-appstorage.md#storagelink), [\@StorageProp](./arkts-appstorage.md#storageprop), [\@LocalStorageLink](./arkts-localstorage.md#localstoragelink), or [\@LocalStorageProp](./arkts-localstorage.md#localstorageprop) decorated variable in its parent component.| 67| Subnode initialization | Supported; can be used to initialize an \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component.| 68| Synchronization with the parent component | Not supported. | 69| Synchronization with descendant components | Two-way with @Consume decorated variables in descendant components. | 70| Access | Private, accessible only within the component. | 71 72 73 **Figure 1** \@Provide initialization rule 74 75 76 77 78 79| \@Consume Transfer/Access| Description | 80| -------------- | ---------------------------------------- | 81| Initialization and update from the parent component | Forbidden. Initialized from the \@Provide decorated variable with the same name or alias. | 82| Subnode initialization | Supported; can be used to initialize an \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component.| 83| Synchronization with the ancestor component | Two-way with the @Provide decorated variable in the ancestor component. | 84| Access | Private, accessible only within the component. | 85 86 87 **Figure 2** \@Consume initialization rule 88 89 90 91 92 93## Observed Changes and Behavior 94 95 96### Observed Changes 97 98- When the decorated variable is of the Boolean, string, or number type, its value change can be observed. 99 100- When the decorated variable is of the class or Object type, its value change and value changes of all its attributes, that is, the attributes that **Object.keys(observedObject)** returns, can be observed. 101 102- When the decorated variable is of the array type, the addition, deletion, and updates of array items can be observed. 103 104- 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 attributes: **setFullYear**, **setMonth**, **setDate**, **setHours**, **setMinutes**, **setSeconds**, **setMilliseconds**, **setTime**, **setUTCFullYear**, **setUTCMonth**, **setUTCDate**, **setUTCHours**, **setUTCMinutes**, **setUTCSeconds**, and **setUTCMilliseconds**. 105 106```ts 107@Component 108struct CompD { 109 @Consume selectedDate: Date; 110 111 build() { 112 Column() { 113 Button(`child increase the day by 1`) 114 .onClick(() => { 115 this.selectedDate.setDate(this.selectedDate.getDate() + 1) 116 }) 117 Button('child update the new date') 118 .margin(10) 119 .onClick(() => { 120 this.selectedDate = new Date('2023-09-09') 121 }) 122 DatePicker({ 123 start: new Date('1970-1-1'), 124 end: new Date('2100-1-1'), 125 selected: this.selectedDate 126 }) 127 } 128 } 129} 130 131@Entry 132@Component 133struct CompA { 134 @Provide selectedDate: Date = new Date('2021-08-08') 135 136 build() { 137 Column() { 138 Button('parent increase the day by 1') 139 .margin(10) 140 .onClick(() => { 141 this.selectedDate.setDate(this.selectedDate.getDate() + 1) 142 }) 143 Button('parent update the new date') 144 .margin(10) 145 .onClick(() => { 146 this.selectedDate = new Date('2023-07-07') 147 }) 148 DatePicker({ 149 start: new Date('1970-1-1'), 150 end: new Date('2100-1-1'), 151 selected: this.selectedDate 152 }) 153 CompD() 154 } 155 } 156} 157``` 158 159- 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). 160 161- 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). 162 163### Framework Behavior 164 1651. Initial render: 166 1. The \@Provide decorated variable is passed to all child components of the owning component in map mode. 167 2. If an \@Consume decorated variable is used in a child component, the system checks the map for a matching \@Provide decorated variable based on the variable name or alias. If no matching variable is found, the framework throws a JS error. 168 3. The process of initializing the @Consume decorated variable is similar to that of initializing the @State/@Link decorated variable. The @Consume decorated variable saves the matching @Provide decorated variable found in the map and registers itself with the @Provide decorated variable. 169 1702. When the \@Provide decorated variable is updated: 171 1. The system traverses and updates all system components (**elementid**) and state variable (\@Consume) that depend on the \@Provide decorated variable, with which the \@Consume decorated variable has registered itself on initial render. 172 2. After the \@Consume decorated variable is updated in all owning child components, all system components (**elementId**) that depend on the \@Consume decorated variable are updated. In this way, changes to the \@Provide decorated variable are synchronized to the \@Consume decorated variable. 173 1743. When the \@Consume decorated variable is updated: 175 176 As can be learned from the initial render procedure, the \@Consume decorated variable holds an instance of \@Provide. After the \@Consume decorated variable is updated, the update method of \@Provide is called to synchronize the changes to \@Provide. 177 178 179 180 181## Constraints 182 1831. The **key** parameter of \@Provider and \@Consumer must be of the string type. Otherwise, an error is reported during compilation. 184 185```ts 186// Incorrect format. An error is reported during compilation. 187let change: number = 10; 188@Provide(change) message: string = 'Hello'; 189 190// Correct format. 191let change: string = 'change'; 192@Provide(change) message: string = 'Hello'; 193``` 194 1952. Variables decorated by \@Consume cannot be initialized locally or using constructor parameters. Otherwise, an error is reported during compilation. \@Consume can be initialized only by matching the corresponding \@Provide variable based on the key. 196 197[Negative example] 198 199```ts 200@Component 201struct Child { 202 @Consume msg: string; 203 // Incorrect format. Local initialization is not allowed. 204 @Consume msg1: string = 'Hello'; 205 206 build() { 207 Text(this.msg) 208 } 209} 210 211@Entry 212@Component 213struct Example { 214 @Provide message: string = 'Hello'; 215 216 build() { 217 Column() { 218 // Incorrect format. External initialization is not allowed. 219 Child({msg: 'Hello'}) 220 } 221 } 222} 223``` 224 225[Positive example] 226 227```ts 228@Component 229struct Child { 230 @Consume num: number; 231 232 build() { 233 Column() { 234 Text(`Value of num: ${this.num}`) 235 } 236 } 237} 238 239@Entry 240@Component 241struct Parent { 242 @Provide num: number = 10; 243 244 build() { 245 Column() { 246 Text(`Value of num: ${this.num}`) 247 Child() 248 } 249 } 250} 251``` 252 2533. \@When the **key** of \@Provide is defined repeatedly, the framework throws a runtime error to remind you. If you need to define the **key** repeatedly, use [allowoverride](#support-for-the-allowoverride-parameter). 254 255```ts 256// Incorrect format. "a" is defined repeatedly. 257@Provide('a') count: number = 10; 258@Provide('a') num: number = 10; 259 260// Correct format. 261@Provide('a') count: number = 10; 262@Provide('b') num: number = 10; 263``` 264 2654. If you do not define the \@Provide variable of the corresponding key when initializing the \@Consume variable, the framework throws a runtime error, indicating that the \@Consume variable fails to be initialized because the \@Provide variable of the corresponding key cannot be found. 266 267[Negative example] 268 269```ts 270@Component 271struct Child { 272 @Consume num: number; 273 274 build() { 275 Column() { 276 Text(`Value of num: ${this.num}`) 277 } 278 } 279} 280 281@Entry 282@Component 283struct Parent { 284 // Incorrect format. @Provide is missing. 285 num: number = 10; 286 287 build() { 288 Column() { 289 Text(`Value of num: ${this.num}`) 290 Child() 291 } 292 } 293} 294``` 295 296[Positive example] 297 298```ts 299@Component 300struct Child { 301 @Consume num: number; 302 303 build() { 304 Column() { 305 Text(`Value of num: ${this.num}`) 306 } 307 } 308} 309 310@Entry 311@Component 312struct Parent { 313 // Correct format. 314 @Provide num: number = 10; 315 316 build() { 317 Column() { 318 Text(`Value of num: ${this.num}`) 319 Child() 320 } 321 } 322} 323``` 324 3255. \@Provide and \@Consume cannot decorate variables of the function type. Otherwise, the framework throws a runtime error. 326 327 328## Application Scenarios 329 330The following example shows the two-way synchronization between \@Provide and \@Consume decorated variables. When the buttons in the **CompA** and **CompD** components are clicked, the changes to **reviewVotes** are synchronized to the **CompA** and **CompD** components. 331 332 333 334```ts 335@Component 336struct CompD { 337 // The @Consume decorated variable is bound to the @Provide decorated variable in its ancestor component CompA under the same attribute name. 338 @Consume reviewVotes: number; 339 340 build() { 341 Column() { 342 Text(`reviewVotes(${this.reviewVotes})`) 343 Button(`reviewVotes(${this.reviewVotes}), give +1`) 344 .onClick(() => this.reviewVotes += 1) 345 } 346 .width('50%') 347 } 348} 349 350@Component 351struct CompC { 352 build() { 353 Row({ space: 5 }) { 354 CompD() 355 CompD() 356 } 357 } 358} 359 360@Component 361struct CompB { 362 build() { 363 CompC() 364 } 365} 366 367@Entry 368@Component 369struct CompA { 370 // @Provide decorated variable reviewVotes is provided by the entry component CompA. 371 @Provide reviewVotes: number = 0; 372 373 build() { 374 Column() { 375 Button(`reviewVotes(${this.reviewVotes}), give +1`) 376 .onClick(() => this.reviewVotes += 1) 377 CompB() 378 } 379 } 380} 381``` 382 383### Decorating Variables of the Map Type 384 385> **NOTE** 386> 387> \@Provide and \@Consume support the Map type since API version 11. 388 389In this example, the **message** variable is of the Map<number, string> type. After the button is clicked, the value of **message** changes, and the UI is re-rendered. 390 391```ts 392@Component 393struct Child { 394 @Consume message: Map<number, string> 395 396 build() { 397 Column() { 398 ForEach(Array.from(this.message.entries()), (item: [number, string]) => { 399 Text(`${item[0]}`).fontSize(30) 400 Text(`${item[1]}`).fontSize(30) 401 Divider() 402 }) 403 Button('Consume init map').onClick(() => { 404 this.message = new Map([[0, "a"], [1, "b"], [3, "c"]]) 405 }) 406 Button('Consume set new one').onClick(() => { 407 this.message.set(4, "d") 408 }) 409 Button('Consume clear').onClick(() => { 410 this.message.clear() 411 }) 412 Button('Consume replace the first item').onClick(() => { 413 this.message.set(0, "aa") 414 }) 415 Button('Consume delete the first item').onClick(() => { 416 this.message.delete(0) 417 }) 418 } 419 } 420} 421 422 423@Entry 424@Component 425struct MapSample { 426 @Provide message: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]) 427 428 build() { 429 Row() { 430 Column() { 431 Button('Provide init map').onClick(() => { 432 this.message = new Map([[0, "a"], [1, "b"], [3, "c"], [4, "d"]]) 433 }) 434 Child() 435 } 436 .width('100%') 437 } 438 .height('100%') 439 } 440} 441``` 442 443### Decorating Variables of the Set Type 444 445> **NOTE** 446> 447> \@Provide and \@Consume support the Set type since API version 11. 448 449In this example, the **message** variable is of the Set\<number\> type. After the button is clicked, the value of **message** changes, and the UI is re-rendered. 450 451```ts 452@Component 453struct Child { 454 @Consume message: Set<number> 455 456 build() { 457 Column() { 458 ForEach(Array.from(this.message.entries()), (item: [number, string]) => { 459 Text(`${item[0]}`).fontSize(30) 460 Divider() 461 }) 462 Button('Consume init set').onClick(() => { 463 this.message = new Set([0, 1, 2, 3, 4]) 464 }) 465 Button('Consume set new one').onClick(() => { 466 this.message.add(5) 467 }) 468 Button('Consume clear').onClick(() => { 469 this.message.clear() 470 }) 471 Button('Consume delete the first one').onClick(() => { 472 this.message.delete(0) 473 }) 474 } 475 .width('100%') 476 } 477} 478 479 480@Entry 481@Component 482struct SetSample { 483 @Provide message: Set<number> = new Set([0, 1, 2, 3, 4]) 484 485 build() { 486 Row() { 487 Column() { 488 Button('Provide init set').onClick(() => { 489 this.message = new Set([0, 1, 2, 3, 4, 5]) 490 }) 491 Child() 492 } 493 .width('100%') 494 } 495 .height('100%') 496 } 497} 498``` 499 500### Support for Union Type 501 502@Provide and @Consume support **undefined**, **null**, and union types. In the following example, the type of **count** is string | undefined. If the attribute or type of **count** is changed when the button in the **Parent** component is clicked, the change will be synced to the child component. 503 504```ts 505@Component 506struct Child { 507 // The @Consume decorated variable is bound to the @Provide decorated variable in its ancestor component Ancestors under the same attribute name. 508 @Consume count: string | undefined; 509 510 build() { 511 Column() { 512 Text(`count(${this.count})`) 513 Button(`count(${this.count}), Child`) 514 .onClick(() => this.count = 'Ancestors') 515 } 516 .width('50%') 517 } 518} 519 520@Component 521struct Parent { 522 build() { 523 Row({ space: 5 }) { 524 Child() 525 } 526 } 527} 528 529@Entry 530@Component 531struct Ancestors { 532 // The @Provide decorated variable count of the union type is provided by the entry component Ancestors for its descendant components. 533 @Provide count: string | undefined = 'Child'; 534 535 build() { 536 Column() { 537 Button(`count(${this.count}), Child`) 538 .onClick(() => this.count = undefined) 539 Parent() 540 } 541 } 542} 543``` 544 545### Support for the allowOverride Parameter 546 547**allowOverride** allows you to override an existing \@Provide decorated variable. 548 549> **NOTE** 550> 551> This API is supported since API version 11. 552 553| Name | Type | Mandatory| Description | 554| ------ | ------ | ---- | ------------------------------------------------------------ | 555| allowOverride | string | No| Enables overriding for \@Provide. When you define an \@Provide decorated variable, use this parameter to override the existing variable with the same name (if any) in the same component tree. If this parameter is not used, defining a variable whose name is already in use will return an error.| 556 557```ts 558@Component 559struct MyComponent { 560 @Provide({allowOverride : "reviewVotes"}) reviewVotes: number = 10; 561} 562``` 563 564```ts 565@Component 566struct GrandSon { 567 // The @Consume decorated variable is bound to the @Provide decorated variable in its ancestor component under the same attribute name. 568 @Consume("reviewVotes") reviewVotes: number; 569 570 build() { 571 Column() { 572 Text(`reviewVotes(${this.reviewVotes})`) // The Text component displays 10. 573 Button(`reviewVotes(${this.reviewVotes}), give +1`) 574 .onClick(() => this.reviewVotes += 1) 575 } 576 .width('50%') 577 } 578} 579 580@Component 581struct Child { 582 @Provide({ allowOverride: "reviewVotes" }) reviewVotes: number = 10; 583 584 build() { 585 Row({ space: 5 }) { 586 GrandSon() 587 } 588 } 589} 590 591@Component 592struct Parent { 593 @Provide({ allowOverride: "reviewVotes" }) reviewVotes: number = 20; 594 595 build() { 596 Child() 597 } 598} 599 600@Entry 601@Component 602struct GrandParent { 603 @Provide("reviewVotes") reviewVotes: number = 40; 604 605 build() { 606 Column() { 607 Button(`reviewVotes(${this.reviewVotes}), give +1`) 608 .onClick(() => this.reviewVotes += 1) 609 Parent() 610 } 611 } 612} 613``` 614 615In the preceding example: 616- The **@Provide("reviewVotes") reviewVotes: number = 40** variable is declared in **GrandParent**. 617- In **Parent**, a child component of **GrandParent**, **allowOverride** is declared for **@Provide** to override the **@Provide("reviewVotes") reviewVotes: number = 40** variable of **GrandParent**. If **allowOverride** is not declared, a runtime error is thrown to indicate that the @Provide decorated variable is already in use. The same case applies to **Child**. 618- The @Consume decorated variable of **GrandSon** is initialized from the @Provide decorated variable of its nearest ancestor under the same attribute name. 619- In this example, **GrandSon** finds in the ancestor **Child** the @Provide decorated variable with the same attribute name. Therefore, the initial value of **@Consume("reviewVotes") reviewVotes: number** is **10**. If an @Provide decorated variable with the same attribute name is not defined in **Child**, **GrandSon** continues its search until it finds the one with the same attribute name. 620- If no such a variable is found when **GrandSon** has reached the root node, an error is thrown to indicate that @Provide could not be found for @Consume initialization. 621 622 623## FAQs 624 625### \@Provide Not Defined Error in the Case of a \@BuilderParam Trailing Closure 626 627In the following example, when **CustomWidget** executes **this.builder()** to create the child component **CustomWidgetChild**, **this** points to **HomePage**. As such, the \@Provide decorated variable of **CustomWidget** cannot be found, and an error is thrown. In light of this, exercise caution with **this** when using \@BuilderParam. 628 629[Incorrect Example] 630 631```ts 632class Tmp { 633 a: string = '' 634} 635 636@Entry 637@Component 638struct HomePage { 639 @Builder 640 builder2($$: Tmp) { 641 Text(`${$$.a}test`) 642 } 643 644 build() { 645 Column() { 646 CustomWidget() { 647 CustomWidgetChild({ builder: this.builder2 }) 648 } 649 } 650 } 651} 652 653@Component 654struct CustomWidget { 655 @Provide('a') a: string = 'abc'; 656 @BuilderParam 657 builder: () => void; 658 659 build() { 660 Column() { 661 Button('Hello').onClick(() => { 662 if (this.a == 'ddd') { 663 this.a = 'abc'; 664 } 665 else { 666 this.a = 'ddd'; 667 } 668 669 }) 670 this.builder() 671 } 672 } 673} 674 675@Component 676struct CustomWidgetChild { 677 @Consume('a') a: string; 678 @BuilderParam 679 builder: ($$: Tmp) => void; 680 681 build() { 682 Column() { 683 this.builder({ a: this.a }) 684 } 685 } 686} 687``` 688 689[Correct Example] 690 691```ts 692class Tmp { 693 name: string = '' 694} 695 696@Entry 697@Component 698struct HomePage { 699 @Provide('name') name: string = 'abc'; 700 701 @Builder 702 builder2($$: Tmp) { 703 Text (`${$$.name}test`) 704 } 705 706 build() { 707 Column() { 708 Button('Hello').onClick(() => { 709 if (this.name == 'ddd') { 710 this.name = 'abc'; 711 } else { 712 this.name = 'ddd'; 713 } 714 }) 715 CustomWidget() { 716 CustomWidgetChild({ builder: this.builder2 }) 717 } 718 } 719 } 720} 721 722@Component 723struct CustomWidget { 724 @BuilderParam 725 builder: () => void; 726 727 build() { 728 this.builder() 729 } 730} 731 732@Component 733struct CustomWidgetChild { 734 @Consume('name') name: string; 735 @BuilderParam 736 builder: ($$: Tmp) => void; 737 738 build() { 739 Column() { 740 this.builder({ name: this.name }) 741 } 742 } 743} 744``` 745 746### Using the a.b(this.object) Format Fails to Trigger UI Re-render 747 748In the **build** method, when the variable decorated by @Provide and @Consume is of the object type and is called using the **a.b(this.object)** format, the native object of **this.object** is passed in the b method. If the property of **this.object** is changed, the UI cannot be re-rendered. In the following example, the UI re-render is not triggered when **this.dog.age** and **this.dog.name** in the component is changed by using a static method or using **this** to call the internal method of the component. 749 750[Negative example] 751 752```ts 753class Animal { 754 name:string; 755 type:string; 756 age: number; 757 758 constructor(name:string, type:string, age:number) { 759 this.name = name; 760 this.type = type; 761 this.age = age; 762 } 763 764 static changeName1(animal:Animal) { 765 animal.name = 'Black'; 766 } 767 static changeAge1(animal:Animal) { 768 animal.age += 1; 769 } 770} 771 772@Entry 773@Component 774struct Demo1 { 775 @Provide dog:Animal = new Animal('WangCai', 'dog', 2); 776 777 changeAge2(animal:Animal) { 778 animal.age += 2; 779 } 780 781 build() { 782 Column({ space:10 }) { 783 Text(`Demo1: This is a ${this.dog.age}-year-old ${this.dog.type} named ${this.dog.name}.`) 784 .fontColor(Color.Red) 785 .fontSize(30) 786 Button('changeAge1') 787 .onClick(()=>{ 788 // The UI cannot be re-rendered using a static method. 789 Animal.changeAge1(this.dog); 790 }) 791 Button('changeAge2') 792 .onClick(()=>{ 793 // The UI cannot be re-rendered using this. 794 this.changeAge2(this.dog); 795 }) 796 Demo2() 797 } 798 } 799} 800 801@Component 802struct Demo2 { 803 804 build() { 805 Column({ space:10 }) { 806 Text(`Demo2.`) 807 .fontColor(Color.Blue) 808 .fontSize(30) 809 Demo3() 810 } 811 } 812} 813 814@Component 815struct Demo3 { 816 @Consume dog:Animal; 817 818 changeName2(animal:Animal) { 819 animal.name = 'White'; 820 } 821 822 build() { 823 Column({ space:10 }) { 824 Text(`Demo3: This is a ${this.dog.age}-year-old ${this.dog.type} named ${this.dog.name}.`) 825 .fontColor(Color.Yellow) 826 .fontSize(30) 827 Button('changeName1') 828 .onClick(()=>{ 829 // The UI cannot be re-rendered using a static method. 830 Animal.changeName1(this.dog); 831 }) 832 Button('changeName2') 833 .onClick(()=>{ 834 // The UI cannot be re-rendered using this. 835 this.changeName2(this.dog); 836 }) 837 } 838 } 839} 840``` 841 842You can add a proxy for **this.dog** to re-render the UI by assigning a value to the variable and then calling the variable. 843 844[Positive example] 845 846```ts 847class Animal { 848 name:string; 849 type:string; 850 age: number; 851 852 constructor(name:string, type:string, age:number) { 853 this.name = name; 854 this.type = type; 855 this.age = age; 856 } 857 858 static changeName1(animal:Animal) { 859 animal.name = 'Black'; 860 } 861 static changeAge1(animal:Animal) { 862 animal.age += 1; 863 } 864} 865 866@Entry 867@Component 868struct Demo1 { 869 @Provide dog:Animal = new Animal('WangCai', 'dog', 2); 870 871 changeAge2(animal:Animal) { 872 animal.age += 2; 873 } 874 875 build() { 876 Column({ space:10 }) { 877 Text(`Demo1: This is a ${this.dog.age}-year-old ${this.dog.type} named ${this.dog.name}.`) 878 .fontColor(Color.Red) 879 .fontSize(30) 880 Button('changeAge1') 881 .onClick(()=>{ 882 // Add a proxy by assigning a value. 883 let a1 = this.dog; 884 Animal.changeAge1(a1); 885 }) 886 Button('changeAge2') 887 .onClick(()=>{ 888 // Add a proxy by assigning a value. 889 let a2 = this.dog; 890 this.changeAge2(a2); 891 }) 892 Demo2() 893 } 894 } 895} 896 897@Component 898struct Demo2 { 899 900 build() { 901 Column({ space:10 }) { 902 Text(`Demo2.`) 903 .fontColor(Color.Blue) 904 .fontSize(30) 905 Demo3() 906 } 907 } 908} 909 910@Component 911struct Demo3 { 912 @Consume dog:Animal; 913 914 changeName2(animal:Animal) { 915 animal.name = 'White'; 916 } 917 918 build() { 919 Column({ space:10 }) { 920 Text(`Demo3: This is a ${this.dog.age}-year-old ${this.dog.type} named ${this.dog.name}.`) 921 .fontColor(Color.Yellow) 922 .fontSize(30) 923 Button('changeName1') 924 .onClick(()=>{ 925 // Add a proxy by assigning a value. 926 let b1 = this.dog; 927 Animal.changeName1(b1); 928 }) 929 Button('changeName2') 930 .onClick(()=>{ 931 // Add a proxy by assigning a value. 932 let b2 = this.dog; 933 this.changeName2(b2); 934 }) 935 } 936 } 937} 938``` 939