• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# wrapBuilder: Encapsulating Global @Builder
2
3When you use multiple global @Builder functions in a struct to implement different UI effects, the code maintenance becomes difficult and the page is not neat. In this case, you can use **wrapBuilder** to encapsulate the global @Builder.
4
5  Before reading this topic, you are advised to read [\@Builder](./arkts-builder.md).
6
7> **NOTE**
8>
9> This API is supported since API version 11.
10
11After the @Builder method assigns a value to a variable or array, the variable or array cannot be used in the UI method.
12
13```ts
14@Builder
15function builderElement() {}
16
17let builderArr: Function[] = [builderElement];
18@Builder
19function testBuilder() {
20  ForEach(builderArr, (item: Function) => {
21    item();
22  })
23}
24```
25
26In the preceding code, **builderArr** is an array consisting of @Builder methods. When each @Builder method is obtained from **ForEach**, the @Builder method cannot be used in the UI method.
27
28 To solve this problem, **wrapBuilder** is introduced as the global @Builder encapsulation function. **wrapBuilder** is a template function that accepts a [global \@Builder decorated function](arkts-builder.md#global-custom-builder-function) as its argument and returns a **WrappedBuilder** object, thereby allowing global \@Builder decorated function to be assigned a value and transferred.
29
30## Available APIs
31
32**wrapBuilder** is a template function that returns a **WrappedBuilder** object.
33
34```ts
35declare function wrapBuilder< Args extends Object[]>(builder: (...args: Args) => void): WrappedBuilder;
36```
37The **WrappedBuilder** object is also a template class.
38
39```ts
40declare class WrappedBuilder< Args extends Object[]> {
41  builder: (...args: Args) => void;
42
43  constructor(builder: (...args: Args) => void);
44}
45```
46
47
48>**NOTE**<br>The template parameter **Args extends Object[]** is a parameter list of the builder function to be wrapped.
49
50Example
51
52```ts
53let builderVar: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder)
54let builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder)] // An array is acceptable.
55```
56
57
58
59## Constraints
60
61**wrapBuilder** only accepts a [global \@Builder decorated function](arkts-builder.md#global-custom-builder-function) as its argument.
62
63Of the **WrappedBuilder** object it returns, the **builder** attribute method can be used only inside the struct.
64
65
66
67## Assigning a Value to a Variable Using the @Builder Method
68
69The **MyBuilder** method decorated by @Builder is used as the parameter of **wrapBuilder**, and **wrapBuilder** is assigned to the **globalBuilder** variable, which solves the problem that the @Builder method cannot be used after being assigned to the variable.
70
71```ts
72@Builder
73function MyBuilder(value: string, size: number) {
74  Text(value)
75    .fontSize(size)
76}
77
78let globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder);
79
80@Entry
81@Component
82struct Index {
83  @State message: string = 'Hello World';
84
85  build() {
86    Row() {
87      Column() {
88        globalBuilder.builder(this.message, 50)
89      }
90      .width('100%')
91    }
92    .height('100%')
93  }
94}
95```
96
97##  Assigning a Value to a Variable by the @Builder Method to Use the Variable in UI Syntax
98
99In this example, the custom component **Index** uses **ForEach** to render different \@Builder functions. You can use the **wrapBuilder** array declared in **builderArr** to present different \@Builder function effects. In this way, the code is neat.
100
101```
102@Builder
103function MyBuilder(value: string, size: number) {
104  Text(value)
105    .fontSize(size)
106}
107
108@Builder
109function YourBuilder(value: string, size: number) {
110  Text(value)
111    .fontSize(size)
112    .fontColor(Color.Pink)
113}
114
115const builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)];
116
117
118@Entry
119@Component
120struct Index {
121  @Builder testBuilder() {
122    ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => {
123      item.builder('Hello World', 30)
124    }
125
126    )
127  }
128
129  build() {
130    Row() {
131      Column() {
132        this.testBuilder()
133      }
134      .width('100%')
135    }
136    .height('100%')
137  }
138}
139```
140
141## Passing Parameters by Reference
142
143If parameters are passed in by reference, the UI re-rendering is triggered.
144
145```ts
146class Tmp {
147  paramA2: string = 'hello';
148}
149
150@Builder function overBuilder(param: Tmp) {
151  Column(){
152    Text(`wrapBuildervalue:${param.paramA2}`)
153  }
154}
155
156const wBuilder: WrappedBuilder<[Tmp]> = wrapBuilder(overBuilder);
157
158@Entry
159@Component
160struct Parent{
161  @State label: Tmp = new Tmp();
162  build(){
163    Column(){
164      wBuilder.builder({paramA2: this.label.paramA2})
165      Button('Click me').onClick(() => {
166        this.label.paramA2 = 'ArkUI';
167      })
168    }
169  }
170}
171```
172
173## FAQs
174
175### wrapBuilder Redefinition Failure
176
177In the same custom component, the same **wrapBuilder** can be initialized only once. In the example, after **builderObj** is initialized through **wrapBuilder(MyBuilderFirst)**, **wrapBuilder(MyBuilderSecond)** does not take effect when a value is assigned to **builderObj** again.
178
179```ts
180@Builder
181function MyBuilderFirst(value: string, size: number) {
182  Text('MyBuilderFirst: ' + value)
183    .fontSize(size)
184}
185
186@Builder
187function MyBuilderSecond(value: string, size: number) {
188  Text('MyBuilderSecond: ' + value)
189    .fontSize(size)
190}
191
192interface BuilderModel {
193  globalBuilder: WrappedBuilder<[string, number]>;
194}
195
196@Entry
197@Component
198struct Index {
199  @State message: string = 'Hello World';
200  @State builderObj: BuilderModel = { globalBuilder: wrapBuilder(MyBuilderFirst) };
201
202  aboutToAppear(): void {
203    setTimeout(() => {
204      // wrapBuilder (MyBuilderSecond) does not take effect.
205      this.builderObj.globalBuilder = wrapBuilder(MyBuilderSecond);
206    },1000)
207  }
208
209  build() {
210    Row() {
211      Column() {
212        this.builderObj.globalBuilder.builder(this.message, 20)
213      }
214      .width('100%')
215    }
216    .height('100%')
217  }
218}
219```
220