1# \@Builder Decorator: Custom Builder Function 2 3ArkUI provides the \@Builder decorator that is a lightweight UI element reuse mechanism. This decorator has a fixed internal UI structure and passes the data only to the user. You can abstract reused UI elements into a method and call the method in the **build** method. 4 5For simplicity, here we refer to an \@Builder decorated function also as a custom builder function. 6 7Before reading this topic, you are advised to read [Basic Syntax Overview](./arkts-basic-syntax-overview.md), [Declarative UI Description](./arkts-declarative-ui-description.md), and [Creating a Custom Component](./arkts-create-custom-components.md). 8 9> **NOTE** 10> 11> This decorator can be used in ArkTS widgets since API version 9. 12> 13> This decorator can be used in atomic services since API version 11. 14 15 16## Rules of Use 17 18The \@Builder decorator can be used for the private custom build function defined in the custom component and global custom build function defined globally. 19 20### Private Custom Builder Function 21 22Syntax: 23 24```ts 25@Entry 26@Component 27struct BuilderDemo { 28 @Builder 29 showTextBuilder() { 30 Text('Hello World') 31 .fontSize(30) 32 .fontWeight(FontWeight.Bold) 33 } 34 @Builder 35 showTextValueBuilder(param: string) { 36 Text(param) 37 .fontSize(30) 38 .fontWeight(FontWeight.Bold) 39 } 40 build() { 41 Column() { 42 // Without parameter. 43 this.showTextBuilder() 44 // With a parameter. 45 this.showTextValueBuilder('Hello @Builder') 46 } 47 } 48} 49``` 50 51Usage: 52 53```ts 54this.showTextBuilder() 55``` 56 57- You can define one or more @Builder decorated methods in a custom component. Such a method is considered as a private, special type of member function of the component. 58 59- Private custom builder functions can be called in custom components, **build()**, and other custom builder functions. 60 61- Inside the custom builder function body, **this** refers to the owning component. Component state variables are accessible from within the custom builder function implementation. Using **this** to access the custom components' state variables is recommended over parameter passing. 62 63 64### Global Custom Builder Function 65 66Syntax: 67 68```ts 69@Builder 70function showTextBuilder() { 71 Text('Hello World') 72 .fontSize(30) 73 .fontWeight(FontWeight.Bold) 74} 75@Entry 76@Component 77struct BuilderDemo { 78 build() { 79 Column() { 80 showTextBuilder() 81 } 82 } 83} 84``` 85 86Usage: 87 88```ts 89showTextBuilder() 90``` 91 92- Use of a global custom builder function is recommended if no own state is involved. 93 94- Global custom builder functions can be called in **build()** and other custom builder functions. 95 96 97## Parameter Passing Rules 98 99For custom builder functions, parameters can be passed [by value](#by-value-parameter-passing) and [by reference](#by-reference-parameter-passing). Both of them must comply with the following rules: 100 101- The parameter type must be the same as the declared parameter type. The **undefined** or **null** constants as well as expressions evaluating to these values are not allowed. 102 103- All parameters must be immutable inside the custom builder function. 104 105- The custom builder function body follows the same [syntax rules](arkts-create-custom-components.md#build-function) as **build()**. 106 107- Parameters are passed by value in all cases except when only one parameter is passed in and the parameter needs to be directly passed to the object literal. 108 109### By-Value Parameter Passing 110 111By default, parameters in the \@Builder decorated functions are passed by value. In this case, when the passed parameter is a state variable, the change of the state variable does not cause UI re-rendering in the \@Builder decorated function. Therefore, when passing state variables, you are advised to use [by-reference parameter passing](#by-reference-parameter-passing). 112 113```ts 114@Builder function overBuilder(paramA1: string) { 115 Row() { 116 Text(`UseStateVarByValue: ${paramA1} `) 117 } 118} 119@Entry 120@Component 121struct Parent { 122 @State label: string = 'Hello'; 123 build() { 124 Column() { 125 overBuilder(this.label) 126 } 127 } 128} 129``` 130 131### By-Reference Parameter Passing 132 133In by-reference parameter passing, state variables can be passed, and the change of these state variables causes the UI re-rendering in the \@Builder decorated method. 134 135```ts 136class Tmp { 137 paramA1: string = ''; 138} 139 140@Builder function overBuilder(params: Tmp) { 141 Row() { 142 Text(`UseStateVarByReference: ${params.paramA1} `) 143 } 144} 145@Entry 146@Component 147struct Parent { 148 @State label: string = 'Hello'; 149 build() { 150 Column() { 151 // When the overBuilder component is called in the parent component, 152 // pass this.label to the overBuilder component by reference. 153 overBuilder({ paramA1: this.label }) 154 Button('Click me').onClick(() => { 155 // After you click "Click me", the UI text changes from "Hello" to "ArkUI". 156 this.label = 'ArkUI'; 157 }) 158 } 159 } 160} 161``` 162 163## Constraints 164 1651. Parameter values cannot be changed in \@Builder decorated functions. Otherwise, the framework throws a runtime error. You can change the parameters in the \@Builder decorated custom components. For details, see [Changing the Input Parameters in the \@Builder Decorated Function](#changing-the-input-parameters-in-the-builder-decorated-function). 166 1672. The \@Builder triggers dynamic UI rendering for only when parameters are passed in by reference. Only one parameter can be passed. For details, see [By-Reference Parameter Passing](#by-reference-parameter-passing). 168 1693. If the \@Builder passes in two or more parameters, dynamic UI rendering is not triggered. For details, see [Two or More Parameters Are Used in \@Builder](#two-or-more-parameters-are-used-in-builder). 170 1714. If the \@Builder passes in parameters by value and by reference, dynamic UI rendering is not triggered. For details, see [Two or More Parameters Are Used in \@Builder](#two-or-more-parameters-are-used-in-builder). 172 1735. \@Builder parameters must be passed in one by one in the form of object literals to trigger dynamic UI rendering. For details, see [Two or More Parameters Are Used in \@Builder](#two-or-more-parameters-are-used-in-builder). 174 175 176## Use Scenarios 177 178### Using Custom Builder Function in Custom Component 179 180Create a private \@Builder method, call this method by using **this.builder()** in **Column**, and change the content of **builder_value** through the **aboutToAppear** lifecycle function and Button click event to dynamically render the UI. 181 182```ts 183@Entry 184@Component 185struct PrivateBuilder { 186 @State builder_value: string = 'Hello'; 187 188 @Builder builder() { 189 Column(){ 190 Text(this.builder_value) 191 .fontSize(30) 192 .fontWeight(FontWeight.Bold) 193 } 194 } 195 196 aboutToAppear(): void { 197 setTimeout(() => { 198 this.builder_value = 'Hello World'; 199 },3000) 200 } 201 202 build() { 203 Row() { 204 Column() { 205 Text(this.builder_value) 206 .fontSize(30) 207 .fontWeight(FontWeight.Bold) 208 this.builder() 209 Button('Click to change builder_value') 210 .onClick(() => { 211 this.builder_value = 'builder_value is clicked' 212 }) 213 } 214 } 215 } 216} 217``` 218 219### Using Global Custom Builder Function 220 221Create a global \@Builder method and call this method by using **overBuilder()** in **Column**. Pass the simple type or complex type parameters in the form of object literals, value changes will trigger UI re-rendering. 222 223```ts 224class ChildTmp { 225 val: number = 1; 226} 227 228class Tmp { 229 str_value: string = 'Hello'; 230 num_value: number = 0; 231 tmp_value: ChildTmp = new ChildTmp(); 232 arrayTmp_value: Array<ChildTmp> = []; 233} 234 235@Builder function overBuilder(param: Tmp) { 236 Column() { 237 Text(`str_value: ${param.str_value}`) 238 Text(`num_value: ${param.num_value}`) 239 Text(`tmp_value: ${param.tmp_value.val}`) 240 ForEach(param.arrayTmp_value, (item: ChildTmp) => { 241 Text(`arrayTmp_value: ${item.val}`) 242 }, (item: ChildTmp) => JSON.stringify(item)) 243 } 244} 245 246@Entry 247@Component 248struct Parent { 249 @State objParam: Tmp = new Tmp(); 250 build() { 251 Column() { 252 Text('Render the UI by calling the @Builder') 253 .fontSize(20) 254 overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value, 255 tmp_value: this.objParam.tmp_value, arrayTmp_value: this.objParam.arrayTmp_value}) 256 Line() 257 .width('100%') 258 .height(10) 259 .backgroundColor('#000000').margin(10) 260 Button('Click to change parameter').onClick(() => { 261 this.objParam.str_value = 'Hello World'; 262 this.objParam.num_value = 1; 263 this.objParam.tmp_value.val = 8; 264 const child_value: ChildTmp = { 265 val: 2 266 } 267 this.objParam.arrayTmp_value.push(child_value) 268 }) 269 } 270 } 271} 272``` 273 274### Changing the Variables Decorated by the Decorator Triggers UI Re-rendering 275 276In this scenario, @Builder is used only to display the **Text** component instead of directly triggering dynamic UI re-rendering. UI re-rendering is triggered by the value change of the **Text** component listened by the decorator. 277 278```ts 279class Tmp { 280 str_value: string = 'Hello'; 281} 282 283@Entry 284@Component 285struct Parent { 286 @State objParam: Tmp = new Tmp(); 287 @State label: string = 'World'; 288 289 @Builder privateBuilder() { 290 Column() { 291 Text(`wrapBuilder str_value: ${this.objParam.str_value}`) 292 Text(`wrapBuilder num: ${this.label}`) 293 } 294 } 295 296 build() { 297 Column() { 298 Text('Render the UI by calling the @Builder') 299 .fontSize(20) 300 this.privateBuilder() 301 Line() 302 .width('100%') 303 .height(10) 304 .backgroundColor('#000000').margin(10) 305 Button('Click to change parameter').onClick(() => { 306 this.objParam.str_value = 'str_value Hello World'; 307 this.label = 'label Hello World' 308 }) 309 } 310 } 311} 312``` 313 314### Using the Global and Local @Builder to Pass in Parameters of the customBuilder Type 315 316When a parameter is of the **customBuilder** type, the defined \@Builder function can be passed in because **customBuilder** is a **Function(() => any)** or **void** type and \@Builder is also a function type. In this case, \@Builder is passed to implement a specific effect. 317 318```ts 319@Builder 320function overBuilder() { 321 Row() { 322 Text('Global Builder') 323 .fontSize(30) 324 .fontWeight(FontWeight.Bold) 325 } 326} 327 328@Entry 329@Component 330struct customBuilderDemo { 331 @State arr: number[] = [0, 1, 2, 3, 4]; 332 333 @Builder 334 privateBuilder() { 335 Row() { 336 Text('Local Builder') 337 .fontSize(30) 338 .fontWeight(FontWeight.Bold) 339 } 340 } 341 342 build() { 343 Column() { 344 List({ space: 10 }) { 345 ForEach(this.arr, (item: number) => { 346 ListItem() { 347 Text(`${item}`) 348 .width('100%') 349 .height(100) 350 .fontSize(16) 351 .textAlign(TextAlign.Center) 352 .borderRadius(10) 353 .backgroundColor(0xFFFFFF) 354 } 355 .swipeAction({ 356 start: { 357 builder: overBuilder() 358 }, 359 end: { 360 builder: () => { 361 this.privateBuilder() 362 } 363 } 364 }) 365 }, (item: number) => JSON.stringify(item)) 366 } 367 } 368 } 369} 370``` 371 372### Nesting of Multi-layer \@Builder Method 373 374Call the custom component or other \@Builder methods in the \@Builder method to implement a nesting of multiple \@Builder methods. To trigger the dynamic UI re-rendering in the innermost \@Builder, you should ensure that \@Builder is called by reference at each layer. [\$$](./arkts-two-way-sync.md) can be replaced with another name, which is not a mandatory parameter. 375 376```ts 377class Tmp { 378 paramA1: string = ''; 379} 380 381@Builder function parentBuilder($$: Tmp) { 382 Row() { 383 Column() { 384 Text(`parentBuilder===${$$.paramA1}`) 385 .fontSize(30) 386 .fontWeight(FontWeight.Bold) 387 HelloComponent({message: $$.paramA1}) 388 childBuilder({paramA1: $$.paramA1}) 389 } 390 } 391} 392 393@Component 394struct HelloComponent { 395 @Prop message: string = ''; 396 397 build() { 398 Row() { 399 Text(`HelloComponent===${this.message}`) 400 .fontSize(30) 401 .fontWeight(FontWeight.Bold) 402 } 403 } 404} 405 406@Builder 407function childBuilder($$: Tmp) { 408 Row() { 409 Column() { 410 Text(`childBuilder===${$$.paramA1}`) 411 .fontSize(30) 412 .fontWeight(FontWeight.Bold) 413 HelloChildComponent({message: $$.paramA1}) 414 grandsonBuilder({paramA1: $$.paramA1}) 415 } 416 } 417} 418 419@Component 420struct HelloChildComponent { 421 @Prop message: string = ''; 422 build() { 423 Row() { 424 Text(`HelloChildComponent===${this.message}`) 425 .fontSize(30) 426 .fontWeight(FontWeight.Bold) 427 } 428 } 429} 430 431@Builder function grandsonBuilder($$: Tmp) { 432 Row() { 433 Column() { 434 Text(`grandsonBuilder===${$$.paramA1}`) 435 .fontSize(30) 436 .fontWeight(FontWeight.Bold) 437 HelloGrandsonComponent({message: $$.paramA1}) 438 } 439 } 440} 441 442@Component 443struct HelloGrandsonComponent { 444 @Prop message: string; 445 build() { 446 Row() { 447 Text(`HelloGrandsonComponent===${this.message}`) 448 .fontSize(30) 449 .fontWeight(FontWeight.Bold) 450 } 451 } 452} 453 454@Entry 455@Component 456struct Parent { 457 @State label: string = 'Hello'; 458 build() { 459 Column() { 460 parentBuilder({paramA1: this.label}) 461 Button('Click me').onClick(() => { 462 this.label = 'ArkUI'; 463 }) 464 } 465 } 466} 467``` 468 469### Using \@Builder Functions Together with the Decorators in V2 470 471Use the global @Builder and local @Builder in the @ComponentV2 decorated custom components and use the @ObservedV2 and @Trace decorators to listen for specific value changes to trigger UI re-rendering. 472 473```ts 474@ObservedV2 475class Info { 476 @Trace name: string = ''; 477 @Trace age: number = 0; 478} 479 480@Builder 481function overBuilder(param: Info) { 482 Column() { 483 Text('Global @Builder name :${param.name}`) 484 .fontSize(30) 485 .fontWeight(FontWeight.Bold) 486 Text('Global @Builder age :${param.age}`) 487 .fontSize(30) 488 .fontWeight(FontWeight.Bold) 489 } 490} 491 492@ComponentV2 493struct ChildPage { 494 @Require @Param childInfo: Info; 495 build() { 496 overBuilder({name: this.childInfo.name, age: this.childInfo.age}) 497 } 498} 499 500@Entry 501@ComponentV2 502struct ParentPage { 503 info1: Info = { name: "Tom", age: 25 }; 504 @Local info2: Info = { name: "Tom", age: 25 }; 505 506 @Builder 507 privateBuilder() { 508 Column() { 509 Text('Local @Builder name :${this.info1.name}`) 510 .fontSize(30) 511 .fontWeight(FontWeight.Bold) 512 Text('Local @Builder age :${this.info1.age}`) 513 .fontSize(30) 514 .fontWeight(FontWeight.Bold) 515 } 516 } 517 518 build() { 519 Column() { 520 Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1 521 .fontSize(30) 522 .fontWeight(FontWeight.Bold) 523 this.privateBuilder() // Call the local @Builder. 524 Line() 525 .width('100%') 526 .height(10) 527 .backgroundColor('#000000').margin(10) 528 Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text2 529 .fontSize(30) 530 .fontWeight(FontWeight.Bold) 531 overBuilder({ name: this.info2.name, age: this.info2.age}) // Call the global @Builder. 532 Line() 533 .width('100%') 534 .height(10) 535 .backgroundColor('#000000').margin(10) 536 Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1 537 .fontSize(30) 538 .fontWeight(FontWeight.Bold) 539 ChildPage ({childInfo: this.info1}) // Call the custom component. 540 Line() 541 .width('100%') 542 .height(10) 543 .backgroundColor('#000000').margin(10) 544 Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text2 545 .fontSize(30) 546 .fontWeight(FontWeight.Bold) 547 ChildPage ({childInfo: this.info2}) // Call the custom component. 548 Line() 549 .width('100%') 550 .height(10) 551 .backgroundColor('#000000').margin(10) 552 Button("change info1&info2") 553 .onClick(() => { 554 this.info1 = { name: "Cat", age: 18}; // Text1 is not re-rendered because no decorator is used to listen for value changes. 555 this.info2 = { name: "Cat", age: 18}; // Text2 is re-rendered because a decorator is used to listen for value changes. 556 }) 557 } 558 } 559} 560``` 561 562## FAQs 563 564### Two or More Parameters Are Used in \@Builder 565 566When two or more parameters are used, the value change does not trigger the UI re-rendering even if the parameters are passed in the form of object literals. 567 568[Negative Example] 569 570```ts 571class GlobalTmp { 572 str_value: string = 'Hello'; 573} 574 575@Builder function overBuilder(param: GlobalTmp, num: number) { 576 Column() { 577 Text(`str_value: ${param.str_value}`) 578 Text(`num: ${num}`) 579 } 580} 581 582@Entry 583@Component 584struct Parent { 585 @State objParam: GlobalTmp = new GlobalTmp(); 586 @State num: number = 0; 587 build() { 588 Column() { 589 Text('Render the UI by calling the @Builder') 590 .fontSize(20) 591 // Two parameters are used, which is incorrect. 592 overBuilder({str_value: this.objParam.str_value}, this.num) 593 Line() 594 .width('100%') 595 .height(10) 596 .backgroundColor('#000000').margin(10) 597 Button('Click to change parameter').onClick(() => { 598 this.objParam.str_value = 'Hello World'; 599 this.num = 1; 600 }) 601 } 602 } 603} 604``` 605 606[Negative Example] 607 608```ts 609class GlobalTmp { 610 str_value: string = 'Hello'; 611} 612class SecondTmp { 613 num_value: number = 0; 614} 615@Builder function overBuilder(param: GlobalTmp, num: SecondTmp) { 616 Column() { 617 Text(`str_value: ${param.str_value}`) 618 Text(`num: ${num.num_value}`) 619 } 620} 621 622@Entry 623@Component 624struct Parent { 625 @State strParam: GlobalTmp = new GlobalTmp(); 626 @State numParam: SecondTmp = new SecondTmp(); 627 build() { 628 Column() { 629 Text('Render the UI by calling the @Builder') 630 .fontSize(20) 631 // Two parameters are used, which is incorrect. 632 overBuilder({str_value: this.strParam.str_value}, {num_value: this.numParam.num_value}) 633 Line() 634 .width('100%') 635 .height(10) 636 .backgroundColor('#000000').margin(10) 637 Button('Click to change parameter').onClick(() => { 638 this.strParam.str_value = 'Hello World'; 639 this.numParam.num_value = 1; 640 }) 641 } 642 } 643} 644``` 645 646Only one parameter can be used in the \@Builder. When one parameter is passed in the form of object literals, the value change triggers the UI re-rendering. 647 648[Positive Example] 649 650```ts 651class GlobalTmp { 652 str_value: string = 'Hello'; 653 num_value: number = 0; 654} 655@Builder function overBuilder(param: GlobalTmp) { 656 Column() { 657 Text(`str_value: ${param.str_value}`) 658 Text(`num: ${param.num_value}`) 659 } 660} 661 662@Entry 663@Component 664struct Parent { 665 @State objParam: GlobalTmp = new GlobalTmp(); 666 build() { 667 Column() { 668 Text('Render the UI by calling the @Builder') 669 .fontSize(20) 670 overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value}) 671 Line() 672 .width('100%') 673 .height(10) 674 .backgroundColor('#000000').margin(10) 675 Button('Click to change parameter').onClick(() => { 676 this.objParam.str_value = 'Hello World'; 677 this.objParam.num_value = 1; 678 }) 679 } 680 } 681} 682``` 683 684### Using the @ComponentV2 Decorator to Trigger Dynamic Re-render 685 686In the way of passing parameters by value, the @ObservedV2 and @Trace decorators can be used together in the @ComponentV2 decorated custom component to re-render the UI. 687 688[Negative Example] 689 690In the @ComponentV2 decorated custom component, the use of simple data types cannot trigger UI re-render. 691 692```ts 693@ObservedV2 694class ParamTmp { 695 @Trace count : number = 0; 696} 697 698@Builder 699function renderNumber(paramNum: number) { 700 Text(`paramNum : ${paramNum}`) 701 .fontSize(30) 702 .fontWeight(FontWeight.Bold) 703} 704 705@Entry 706@ComponentV2 707struct PageBuilder { 708 @Local class_value: ParamTmp = new ParamTmp(); 709 // Using simple data type cannot trigger UI re-render 710 @Local num_value: number = 0; 711 private progressTimer: number = -1; 712 713 aboutToAppear(): void { 714 this.progressTimer = setInterval(() => { 715 if (this.class_value.count < 100) { 716 this.class_value.count += 5; 717 this.num_value += 5; 718 } else { 719 clearInterval(this.progressTimer); 720 } 721 }, 500); 722 } 723 724 build() { 725 Column() { 726 renderNumber(this.num_value) 727 } 728 .width('100%') 729 .height('100%') 730 .padding(50) 731 } 732} 733``` 734 735[Positive Example] 736 737In @ComponentV2, only the @ObservedV2 decorated **ParamTmp** class and the @Trace decorated **count** property can trigger the UI re-render. 738 739```ts 740@ObservedV2 741class ParamTmp { 742 @Trace count : number = 0; 743} 744 745@Builder 746function renderText(param: ParamTmp) { 747 Column() { 748 Text(`param : ${param.count}`) 749 .fontSize(20) 750 .fontWeight(FontWeight.Bold) 751 } 752} 753 754@Builder 755function renderMap(paramMap: Map<string,number>) { 756 Text(`paramMap : ${paramMap.get('name')}`) 757 .fontSize(20) 758 .fontWeight(FontWeight.Bold) 759} 760 761@Builder 762function renderSet(paramSet: Set<number>) { 763 Text(`paramSet : ${paramSet.size}`) 764 .fontSize(20) 765 .fontWeight(FontWeight.Bold) 766} 767 768@Builder 769function renderNumberArr(paramNumArr: number[]) { 770 Text(`paramNumArr : ${paramNumArr[0]}`) 771 .fontSize(20) 772 .fontWeight(FontWeight.Bold) 773} 774 775@Entry 776@ComponentV2 777struct PageBuilder { 778 @Local builderParams: ParamTmp = new ParamTmp(); 779 @Local map_value: Map<string,number> = new Map(); 780 @Local set_value: Set<number> = new Set([0]); 781 @Local numArr_value: number[] = [0]; 782 private progressTimer: number = -1; 783 784 aboutToAppear(): void { 785 this.progressTimer = setInterval(() => { 786 if (this.builderParams.count < 100) { 787 this.builderParams.count += 5; 788 this.map_value.set('name', this.builderParams.count); 789 this.set_value.add(this.builderParams.count); 790 this.numArr_value[0] = this.builderParams.count; 791 } else { 792 clearInterval(this.progressTimer); 793 } 794 }, 500); 795 } 796 797 @Builder 798 localBuilder() { 799 Column() { 800 Text(`localBuilder : ${this.builderParams.count}`) 801 .fontSize(20) 802 .fontWeight(FontWeight.Bold) 803 } 804 } 805 806 build() { 807 Column() { 808 this.localBuilder() 809 Text(`builderParams :${this.builderParams.count}`) 810 .fontSize(20) 811 .fontWeight(FontWeight.Bold) 812 renderText(this.builderParams) 813 renderText({ count: this.builderParams.count }) 814 renderMap(this.map_value) 815 renderSet(this.set_value) 816 renderNumberArr(this.numArr_value) 817 } 818 .width('100%') 819 .height('100%') 820 } 821} 822``` 823 824### Changing the Input Parameters in the \@Builder Decorated Function 825 826[Negative Example] 827 828```ts 829interface Temp { 830 paramA: string; 831} 832 833@Builder function overBuilder(param: Temp) { 834 Row() { 835 Column() { 836 Button(`overBuilder === ${param.paramA}`) 837 .onClick(() => { 838 // Incorrect format. Parameter values cannot be changed in the function decorated by @Builder. 839 param.paramA = 'Yes'; 840 }) 841 } 842 } 843} 844 845@Entry 846@Component 847struct Parent { 848 @State label: string = 'Hello'; 849 850 build() { 851 Column() { 852 overBuilder({paramA: this.label}) 853 Button('click me') 854 .onClick(() => { 855 this.label = 'ArkUI'; 856 }) 857 } 858 } 859} 860``` 861 862[Positive Example] 863 864```ts 865interface Temp { 866 paramA: string; 867} 868 869@Builder function overBuilder(param: Temp) { 870 Row() { 871 Column() { 872 Button(`overBuilder === ${param.paramA}`) 873 } 874 } 875} 876 877@Entry 878@Component 879struct Parent { 880 @State label: string = 'Hello'; 881 882 build() { 883 Column() { 884 overBuilder({paramA: this.label}) 885 Button('click me') 886 .onClick(() => { 887 this.label = 'ArkUI'; 888 }) 889 } 890 } 891} 892``` 893