1# \@BuilderParam Decorator: @Builder Function Reference 2 3 4In certain circumstances, you may need to add a specific feature, such as a click-to-jump action, to a custom component. However, embedding an event method directly in a component will add the feature to all places where the component is imported. This is where the \@BuilderParam decorator comes into the picture. \@BuilderParam is used to decorate a custom component variable of type Reference to an [\@Builder](./arkts-builder.md) method (@BuilderParam is used to undertake the @Builder function). When initializing a custom component, you can add the specific feature to it by assigning a value to the variable. This decorator can be used to declare an element of any UI description, similar to a slot placeholder. 5 6 7> **NOTE** 8> 9> This decorator can be used in ArkTS widgets since API version 9. 10> 11> This decorator can be used in atomic services since API version 11. 12 13## Rules of Use 14 15 16### Initializing \@BuilderParam Decorated Methods 17 18An \@BuilderParam decorated method can be initialized only by an \@Builder function reference. If this decorator is used together with [\@Require](arkts-require.md) in API version 11, the parent component must construct input parameters. 19 20- Local initialization with the owning component's custom \@Builder function reference or a global \@Builder function reference 21 22 ```ts 23 @Builder function overBuilder() {} 24 25 @Component 26 struct Child { 27 @Builder doNothingBuilder() {}; 28 29 // Use the custom builder function of the custom component for @BuilderParam initialization. 30 @BuilderParam customBuilderParam: () => void = this.doNothingBuilder; 31 // Use the global custom builder function for @BuilderParam initialization. 32 @BuilderParam customOverBuilderParam: () => void = overBuilder; 33 build(){} 34 } 35 ``` 36 37- Initialization from the parent component 38 39 ```ts 40 @Component 41 struct Child { 42 @Builder customBuilder() {}; 43 // Use the @Builder decorated method in the parent component for @BuilderParam initialization. 44 @BuilderParam customBuilderParam: () => void = this.customBuilder; 45 46 build() { 47 Column() { 48 this.customBuilderParam() 49 } 50 } 51 } 52 53 @Entry 54 @Component 55 struct Parent { 56 @Builder componentBuilder() { 57 Text(`Parent builder `) 58 } 59 60 build() { 61 Column() { 62 Child({ customBuilderParam: this.componentBuilder }) 63 } 64 } 65 } 66 ``` 67 **Figure 1** Example effect 68 69  70 71 72- **this** in the function body must point to the correct object. 73 74Example: 75 76 ```ts 77 @Component 78 struct Child { 79 label: string = `Child`; 80 @Builder customBuilder() {}; 81 @Builder customChangeThisBuilder() {}; 82 @BuilderParam customBuilderParam: () => void = this.customBuilder; 83 @BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder; 84 85 build() { 86 Column() { 87 this.customBuilderParam() 88 this.customChangeThisBuilderParam() 89 } 90 } 91 } 92 93 @Entry 94 @Component 95 struct Parent { 96 label: string = `Parent`; 97 98 @Builder componentBuilder() { 99 Text(`${this.label}`) 100 } 101 102 build() { 103 Column() { 104 // When this.componentBuilder() is called, this points to the Parent component decorated by the @Entry. That is, the value of the label variable is Parent. 105 this.componentBuilder() 106 Child({ 107 // Pass this.componentBuilder to @BuilderParam customBuilderParam of the Child component. this points to the Child, that is, the value of the label variable is Child. 108 customBuilderParam: this.componentBuilder, 109 // pass ():void=>{this.componentBuilder () } to @BuilderParam customChangeThisBuilderPara of Child component. 110 // this of the arrow function points to the host object, so the value of the label variable is Parent. 111 customChangeThisBuilderParam: (): void => { this.componentBuilder() } 112 }) 113 } 114 } 115 } 116 ``` 117 **Figure 2** Example effect 118 119  120 121 122## Use Scenarios 123 124 125### Component Initialization Through Parameters 126 127An \@BuilderParam decorated method can be a method with or without parameters. Whether it contains parameters should match that of the assigned \@Builder method. The type of the \@BuilderParam decorated method must also match that of the assigned \@Builder method. 128 129```ts 130class Tmp{ 131 label: string = ''; 132} 133 134@Builder function overBuilder($$: Tmp) { 135 Text($$.label) 136 .width(400) 137 .height(50) 138 .backgroundColor(Color.Green) 139} 140 141@Component 142struct Child { 143 label: string = 'Child'; 144 @Builder customBuilder() {}; 145 // Without parameters. The pointed componentBuilder does not carry parameters either. 146 @BuilderParam customBuilderParam: () => void = this.customBuilder; 147 // With parameters. The pointed overBuilder also carries parameters. 148 @BuilderParam customOverBuilderParam: ($$: Tmp) => void = overBuilder; 149 150 build() { 151 Column() { 152 this.customBuilderParam() 153 this.customOverBuilderParam({label: 'global Builder label' } ) 154 } 155 } 156} 157 158@Entry 159@Component 160struct Parent { 161 label: string = 'Parent'; 162 163 @Builder componentBuilder() { 164 Text(`${this.label}`) 165 } 166 167 build() { 168 Column() { 169 this.componentBuilder() 170 Child({ customBuilderParam: this.componentBuilder, customOverBuilderParam: overBuilder }) 171 } 172 } 173} 174``` 175**Figure 3** Example effect 176 177 178 179 180### Component Initialization Through Trailing Closure 181 182In a custom component, the \@BuilderParam decorated attribute can be initialized using a trailing closure. During initialization, the component name is followed by a pair of braces ({}) to form a trailing closure. 183 184> **NOTE** 185> 186> - In this scenario, the custom component can have only one \@BuilderParam decorated attribute. 187> 188> - In this scenario, custom components do not support universal attributes. 189 190You can pass the content in the trailing closure to \@BuilderParam as an \@Builder decorated method. Example: 191 192 193```ts 194@Component 195struct CustomContainer { 196 @Prop header: string = ''; 197 @Builder closerBuilder(){}; 198 // Use the trailing closure {} (@Builder decorated method) of the parent component for @BuilderParam initialization. 199 @BuilderParam closer: () => void = this.closerBuilder; 200 201 build() { 202 Column() { 203 Text(this.header) 204 .fontSize(30) 205 this.closer() 206 } 207 } 208} 209 210@Builder function specificParam(label1: string, label2: string) { 211 Column() { 212 Text(label1) 213 .fontSize(30) 214 Text(label2) 215 .fontSize(30) 216 } 217} 218 219@Entry 220@Component 221struct CustomContainerUser { 222 @State text: string = 'header'; 223 224 build() { 225 Column() { 226 // Create the CustomContainer component. During initialization, append a pair of braces ({}) to the component name to form a trailing closure. 227 // Used as the parameter passed to CustomContainer @BuilderParam closer: () => void. 228 CustomContainer({ header: this.text }) { 229 Column() { 230 specificParam('testA', 'testB') 231 }.backgroundColor(Color.Yellow) 232 .onClick(() => { 233 this.text = 'changeHeader'; 234 }) 235 } 236 } 237 } 238} 239``` 240**Figure 4** Example effect 241 242 243 244### \@BuilderParam Initialization Through Global and Local \@Builder 245 246In a custom component, the \@BuilderParam decorated variable is used to receive the content passed by the parent component through \@Builder for initialization. The \@Builder of the parent component can use the arrow function to change the object that this points to, therefore, when a \@BuilderParam decorated variable is used, different content is displayed. 247 248```ts 249@Component 250struct ChildPage { 251 label: string = `Child Page`; 252 @Builder customBuilder() {}; 253 @BuilderParam customBuilderParam: () => void = this.customBuilder; 254 @BuilderParam customChangeThisBuilderParam: () => void = this.customBuilder; 255 256 build() { 257 Column() { 258 this.customBuilderParam() 259 this.customChangeThisBuilderParam() 260 } 261 } 262} 263 264const builder_value: string = 'Hello World'; 265@Builder function overBuilder() { 266 Row() { 267 Text(`Global Builder: ${builder_value}`) 268 .fontSize(20) 269 .fontWeight(FontWeight.Bold) 270 } 271} 272 273@Entry 274@Component 275struct ParentPage { 276 label: string = `Parent Page`; 277 278 @Builder componentBuilder() { 279 Row(){ 280 Text(`Local Builder:${this.label}`) 281 .fontSize(20) 282 .fontWeight(FontWeight.Bold) 283 } 284 } 285 286 build() { 287 Column() { 288 // When this.componentBuilder() is called, this points to the **ParentPage** component decorated by the @Entry. Therefore, the value of the label variable is Parent Page. 289 this.componentBuilder() 290 ChildPage({ 291 // Pass this.componentBuilder to @BuilderParam customBuilderParam of ChildPage component. this points to ChildPage, that is, the value of the label variable is Child Page. 292 customBuilderParam: this.componentBuilder, 293 // Pass ():void=>{this.componentBuilder () } to @BuilderParam customChangeThisBuilderPara of ChildPage component. 294 // this of the arrow function points to the host object, so the value of the label variable is Parent Page. 295 customChangeThisBuilderParam: (): void => { this.componentBuilder() } 296 }) 297 Line() 298 .width('100%') 299 .height(10) 300 .backgroundColor('#000000').margin(10) 301 // When the global overBuilder() is called, this points to the entire current page. Therefore, the displayed content is Hello World. 302 overBuilder() 303 ChildPage({ 304 // Pass the global overBuilder to @BuilderParam customBuilderParam of the ChildPage component. this points to the entire current page, that is, the displayed content is Hello World. 305 customBuilderParam: overBuilder, 306 // Pass the global overBuilder to @BuilderParam customChangeThisBuilderParam of the ChildPage component. this points to the entire current page, that is, the displayed content is Hello World. 307 customChangeThisBuilderParam: overBuilder 308 }) 309 } 310 } 311} 312``` 313**Figure 5** Example effect 314 315 316 317## FAQs 318 319### UI Re-rendering Fails When Content Is Changed 320 321When the custom component **ChildPage** is called, \@Builder is passed as a parameter through **this.componentBuilder**. Currently, this points to the custom component. Therefore, if the **label** value is changed inside the parent component, the custom component **ChildPage** cannot detect the change. 322 323[Incorrect Example] 324 325```ts 326@Component 327struct ChildPage { 328 @State label: string = `Child Page`; 329 @Builder customBuilder() {}; 330 @BuilderParam customChangeThisBuilderParam: () => void = this.customBuilder; 331 332 build() { 333 Column() { 334 this.customChangeThisBuilderParam() 335 } 336 } 337} 338 339@Entry 340@Component 341struct ParentPage { 342 @State label: string = `Parent Page`; 343 344 @Builder componentBuilder() { 345 Row(){ 346 Text(`Builder :${this.label}`) 347 .fontSize(20) 348 .fontWeight(FontWeight.Bold) 349 } 350 } 351 352 build() { 353 Column() { 354 ChildPage({ 355 customChangeThisBuilderParam: this.componentBuilder // Incorrect parameter passing. 356 }) 357 Button('Click to change label') 358 .onClick(() => { 359 this.label = 'Hello World'; 360 }) 361 } 362 } 363} 364``` 365 366Use the arrow function to pass the \@Builder to the custom component **ChildPage** and this points to the parent component **ParentPage**. Therefore, if the value of label is changed in the parent component, the **ChildPage** detects the change and renders the UI again. 367 368[Correct Example] 369 370```ts 371@Component 372struct ChildPage { 373 @State label: string = `Child Page`; 374 @Builder customBuilder() {}; 375 @BuilderParam customChangeThisBuilderParam: () => void = this.customBuilder; 376 377 build() { 378 Column() { 379 this.customChangeThisBuilderParam() 380 } 381 } 382} 383 384@Entry 385@Component 386struct ParentPage { 387 @State label: string = `Parent Page`; 388 389 @Builder componentBuilder() { 390 Row(){ 391 Text(`Builder :${this.label}`) 392 .fontSize(20) 393 .fontWeight(FontWeight.Bold) 394 } 395 } 396 397 build() { 398 Column() { 399 ChildPage({ 400 customChangeThisBuilderParam: () => { this.componentBuilder() } 401 }) 402 Button('Click to change label') 403 .onClick(() => { 404 this.label = 'Hello World'; 405 }) 406 } 407 } 408} 409``` 410