1# wrapBuilder: Encapsulating Global @Builder 2 3 When multiple global @Builder functions are used within a single struct to implement different UI effects, code maintenance becomes challenging and the page structure appears cluttered. **wrapBuilder** provides a solution to encapsulate these global builders. 4 5 Before reading this topic, you are advised to read [\@Builder](./arkts-builder.md). 6 7> **NOTE** 8> 9> This feature is supported since API version 11. 10 11When the @Builder method is assigned to a variable or array, it 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 of @Builder methods. When you obtain each @Builder method in the ForEach loop, an issue arises where the @Builder method cannot be used in the UI method. 27 28To address this issue, **wrapBuilder** is introduced as a global @Builder encapsulation function. **wrapBuilder** returns a **WrappedBuilder** object, enabling [global @Builder functions](arkts-builder.md#global-custom-builder-function) to be assigned and passed. 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<Args>; 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)]; // Can be placed in arrays. 55``` 56 57 58 59## Constraints 60 611. **wrapBuilder** only accepts a [global \@Builder decorated function](arkts-builder.md#global-custom-builder-function) as its argument. 62 632. Of the **WrappedBuilder** object it returns, the **builder** attribute method can be used only inside the struct. 64 65## Assigning a Value to a Variable Using the @Builder Method 66 67To solve the issue where an @Builder decorated method (for example, **MyBuilder**) cannot be used after being assigned to a variable, you can pass the method as a parameter to **wrapBuilder**, and then assign the return value of **wrapBuilder** to the variable **globalBuilder**. 68 69```ts 70@Builder 71function MyBuilder(value: string, size: number) { 72 Text(value) 73 .fontSize(size) 74} 75 76let globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder); 77 78@Entry 79@Component 80struct Index { 81 @State message: string = 'Hello World'; 82 83 build() { 84 Row() { 85 Column() { 86 globalBuilder.builder(this.message, 50) 87 } 88 .width('100%') 89 } 90 .height('100%') 91 } 92} 93``` 94 95## Assigning a Value to a Variable by the @Builder Method to Use the Variable in UI Syntax 96 97In this example, the custom component **Index** uses **ForEach** to render different \@Builder functions. You can use the **wrapBuilder** array declared in **builderArr** to achieve different \@Builder function effects. This results in cleaner and more organized code. 98 99``` 100@Builder 101function MyBuilder(value: string, size: number) { 102 Text(value) 103 .fontSize(size) 104} 105 106@Builder 107function YourBuilder(value: string, size: number) { 108 Text(value) 109 .fontSize(size) 110 .fontColor(Color.Pink) 111} 112 113const builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]; 114 115 116@Entry 117@Component 118struct Index { 119 @Builder 120 testBuilder() { 121 ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => { 122 item.builder('Hello World', 30) 123 } 124 125 ) 126 } 127 128 build() { 129 Row() { 130 Column() { 131 this.testBuilder() 132 } 133 .width('100%') 134 } 135 .height('100%') 136 } 137} 138``` 139 140## Passing Parameters by Reference 141 142When parameters are passed by reference, changes to state variables will trigger UI updates inside the @Builder method. 143 144```ts 145class Tmp { 146 paramA2: string = 'hello'; 147} 148 149@Builder 150function 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 163 build() { 164 Column() { 165 wBuilder.builder({ paramA2: this.label.paramA2 }) 166 Button('Click me').onClick(() => { 167 this.label.paramA2 = 'ArkUI'; 168 }) 169 } 170 } 171} 172``` 173 174## FAQs 175 176### Failure of Duplicate wrapBuilder Initialization 177 178In the same custom component, the same **wrapBuilder** can be initialized only once. In the example, after **builderObj** is initialized through **wrapBuilder(MyBuilderFirst)**, re-assigning it with **wrapBuilder(MyBuilderSecond)** will not take effect. 179 180```ts 181@Builder 182function MyBuilderFirst(value: string, size: number) { 183 Text('MyBuilderFirst: ' + value) 184 .fontSize(size) 185} 186 187@Builder 188function MyBuilderSecond(value: string, size: number) { 189 Text('MyBuilderSecond: ' + value) 190 .fontSize(size) 191} 192 193interface BuilderModel { 194 globalBuilder: WrappedBuilder<[string, number]>; 195} 196 197@Entry 198@Component 199struct Index { 200 @State message: string = 'Hello World'; 201 @State builderObj: BuilderModel = { globalBuilder: wrapBuilder(MyBuilderFirst) }; 202 203 aboutToAppear(): void { 204 setTimeout(() => { 205 // wrapBuilder(MyBuilderSecond) does not take effect. 206 this.builderObj.globalBuilder = wrapBuilder(MyBuilderSecond); 207 }, 1000); 208 } 209 210 build() { 211 Row() { 212 Column() { 213 this.builderObj.globalBuilder.builder(this.message, 20) 214 } 215 .width('100%') 216 } 217 .height('100%') 218 } 219} 220``` 221