• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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