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 6> **NOTE** 7> 8> This API is supported since API version 11. 9 10After the @Builder method assigns a value to a variable or array, the variable or array cannot be used in the UI method. 11 12```ts 13@Builder 14function builderElement() {} 15 16let builderArr: Function[] = [builderElement]; 17@Builder 18function testBuilder() { 19 ForEach(builderArr, (item: Function) => { 20 item(); 21 }) 22} 23``` 24 25In 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. 26 27 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. 28 29## Available APIs 30 31**wrapBuilder** is a template function that returns a **WrappedBuilder** object. 32 33```ts 34declare function wrapBuilder< Args extends Object[]>(builder: (...args: Args) => void): WrappedBuilder; 35``` 36The **WrappedBuilder** object is also a template class. 37 38```ts 39declare class WrappedBuilder< Args extends Object[]> { 40 builder: (...args: Args) => void; 41 42 constructor(builder: (...args: Args) => void); 43} 44``` 45 46 47>**NOTE**<br>The template parameter **Args extends Object[]** is a parameter list of the builder function to be wrapped. 48 49Example 50 51```ts 52let builderVar: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder) 53let builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder)] // An array is acceptable. 54``` 55 56## Constraints 57 58**wrapBuilder** only accepts a [global \@Builder decorated function](arkts-builder.md#global-custom-builder-function) as its argument. 59 60Of the **WrappedBuilder** object it returns, the **builder** attribute method can be used only inside the struct. 61 62## Assigning a Value to a Variable Using the @Builder Method 63 64The **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. 65 66```ts 67@Builder 68function MyBuilder(value: string, size: number) { 69 Text(value) 70 .fontSize(size) 71} 72 73let globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder); 74 75@Entry 76@Component 77struct Index { 78 @State message: string = 'Hello World'; 79 80 build() { 81 Row() { 82 Column() { 83 globalBuilder.builder(this.message, 50) 84 } 85 .width('100%') 86 } 87 .height('100%') 88 } 89} 90``` 91 92## Assigning a Value to a Variable by the @Builder Method to Use the Variable in UI Syntax 93 94In 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. 95 96``` 97@Builder 98function MyBuilder(value: string, size: number) { 99 Text(value) 100 .fontSize(size) 101} 102 103@Builder 104function YourBuilder(value: string, size: number) { 105 Text(value) 106 .fontSize(size) 107 .fontColor(Color.Pink) 108} 109 110const builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]; 111 112 113@Entry 114@Component 115struct Index { 116 @Builder testBuilder() { 117 ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => { 118 item.builder('Hello World', 30) 119 } 120 121 ) 122 } 123 124 build() { 125 Row() { 126 Column() { 127 this.testBuilder() 128 } 129 .width('100%') 130 } 131 .height('100%') 132 } 133} 134``` 135 136## Passing Parameters by Reference 137 138If parameters are passed in by reference, the UI re-rendering is triggered. 139 140```ts 141class Tmp { 142 paramA2: string = 'hello'; 143} 144 145@Builder function overBuilder(param: Tmp) { 146 Column(){ 147 Text(`wrapBuildervalue:${param.paramA2}`) 148 } 149} 150 151const wBuilder: WrappedBuilder<[Tmp]> = wrapBuilder(overBuilder); 152 153@Entry 154@Component 155struct Parent{ 156 @State label: Tmp = new Tmp(); 157 build(){ 158 Column(){ 159 wBuilder.builder({paramA2: this.label.paramA2}) 160 Button('Click me').onClick(() => { 161 this.label.paramA2 = 'ArkUI'; 162 }) 163 } 164 } 165} 166``` 167 168## Incorrect Usage 169 170### wrapBuilder Accepts Only a Global Function Decorated by @Builder 171 172```ts 173function MyBuilder() { 174 175} 176 177const globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder); 178 179@Entry 180@Component 181struct Index { 182 @State message: string = 'Hello World'; 183 184 build() { 185 Row() { 186 Column() { 187 Text(this.message) 188 .fontSize(50) 189 .fontWeight(FontWeight.Bold) 190 globalBuilder.builder(this.message, 30) 191 } 192 .width('100%') 193 } 194 .height('100%') 195 } 196} 197``` 198 199### wrapBuilder Redefinition Failure 200 201After **builderObj** is initialized and defined through **wrapBuilder(MyBuilderFirst)**, if you assign a new value to **builderObj**, **wrapBuilder(MyBuilderSecond)** does not take effect. Only the first defined **wrapBuilder(MyBuilderFirst)** takes effect. 202 203```ts 204@Builder 205function MyBuilderFirst(value: string, size: number) { 206 Text('MyBuilderFirst: ' + value) 207 .fontSize(size) 208} 209 210@Builder 211function MyBuilderSecond(value: string, size: number) { 212 Text('MyBuilderSecond: ' + value) 213 .fontSize(size) 214} 215 216interface BuilderModel { 217 globalBuilder: WrappedBuilder<[string, number]>; 218} 219 220@Entry 221@Component 222struct Index { 223 @State message: string = 'Hello World'; 224 @State builderObj: BuilderModel = { globalBuilder: wrapBuilder(MyBuilderFirst) }; 225 226 aboutToAppear(): void { 227 setTimeout(() => { 228 this.builderObj.globalBuilder = wrapBuilder(MyBuilderSecond); 229 },1000) 230 } 231 232 build() { 233 Row() { 234 Column() { 235 this.builderObj.globalBuilder.builder(this.message, 20) 236 } 237 .width('100%') 238 } 239 .height('100%') 240 } 241} 242``` 243