1# \@LocalBuilder decorator: Maintaining the Parent-Child Relationship Between Component and State Management 2 3When use @Builder to pass data, the parent-child relationship of components is considered. After **bind(this)** is used, the parent-child relationship of components is inconsistent with that of state management. As a result, the @LocalBuilder decorator is used to fix the inconsistency. @LocalBuilder has the same features as local @Builder and provides a better determination of the parent-child relationship of components and state management. 4 5 6> **NOTE** 7> 8> This decorator is supported since API version 12. 9> 10> 11 12## How to Use 13 14 15### Local Custom Builder Function 16 17Syntax: 18 19 20```ts 21@LocalBuilder MyBuilderFunction() { ... } 22``` 23 24Usage: 25 26 27```ts 28this.MyBuilderFunction() 29``` 30 31- One or more @LocalBuilder methods can be defined in a custom component. The methods are considered as private and special member functions of the component. 32- The custom builder function can be called from the **build** method or another custom builder function in the same component only. 33- 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. 34 35## Constraints 36 37- @LocalBuilder can be declared only within the component to which it belongs. Global declaration is not allowed. 38 39- @LocalBuilder cannot be used by built-in decorators and custom decorators. 40 41- Static methods in a custom component cannot be used together with @LocalBuilder. 42 43## Differences Between @LocalBuilder and Local @Builder 44 45To change the pointed object of **this**, **bind(this)** used in the local @Builder will cause inconsistent parent-child relationship between the component and the state management. However, this problem does not exist in the @LocalBuilder. For details, see [Differences between @LocalBuilder and @Builder](arkts-localBuilder.md#differences-between-localbuilder-and-builder). 46 47## Parameter Passing Rules 48 49For @LocalBuilder 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: 50 51- 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. 52 53- All parameters must be immutable inside the @LocalBuilder function. 54 55- The \@LocalBuilder function body follows the same [syntax rules](arkts-create-custom-components.md#build-function) as the **build()** function. 56 57- 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. 58 59 60### By-Reference Parameter Passing 61 62In by-reference parameter passing, state variables can be passed, and the change of these state variables causes the UI re-rendering in the \@LocalBuilder decorated method. 63 64Use scenario: 65 66The @LocalBuilder method in the **Parent** component is called in the **build** function to pass the parameters by keys. When you click **Click me**, the **Text** content in the @LocalBuilder changes with the state variable. 67 68```ts 69class ReferenceType { 70 paramString: string = ''; 71} 72 73@Entry 74@Component 75struct Parent { 76 @State variableValue: string = 'Hello World'; 77 78 @LocalBuilder 79 citeLocalBuilder(params: ReferenceType) { 80 Row() { 81 Text(`UseStateVarByReference: ${params.paramString} `) 82 } 83 }; 84 85 build() { 86 Column() { 87 this.citeLocalBuilder({ paramString: this.variableValue }); 88 Button('Click me').onClick(() => { 89 this.variableValue = 'Hi World'; 90 }) 91 } 92 } 93} 94``` 95 96When parameters are passed by reference, if a custom component is called within the\@LocalBuilder method, ArkUI provides [$$](arkts-two-way-sync.md) as the paradigm for passing parameters by reference. 97 98Use scenario: 99 100The @LocalBuilder method in the **Parent** component is called in the custom component to pass the parameters by reference. When the value of a state variable in the **Parent** component changes, the **message** of the custom component **HelloComponent** in the @LocalBuilder method also changes. 101 102```ts 103class ReferenceType { 104 paramString: string = ''; 105} 106 107@Component 108struct HelloComponent { 109 @Prop message: string; 110 111 build() { 112 Row() { 113 Text(`HelloComponent===${this.message}`); 114 } 115 } 116} 117 118@Entry 119@Component 120struct Parent { 121 @State variableValue: string = 'Hello World'; 122 123 @LocalBuilder 124 citeLocalBuilder($$: ReferenceType) { 125 Row() { 126 Column() { 127 Text(`citeLocalBuilder===${$$.paramString}`); 128 HelloComponent({ message: $$.paramString }); 129 } 130 } 131 } 132 133 build() { 134 Column() { 135 this.citeLocalBuilder({ paramString: this.variableValue }); 136 Button('Click me').onClick(() => { 137 this.variableValue = 'Hi World'; 138 }) 139 } 140 } 141} 142``` 143 144 145### By-Value Parameter Passing 146 147By default, parameters in the \@LocalBuilder 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 \@LocalBuilder decorated function. Therefore, when passing state variables, you are advised to use [by-reference parameter passing](#by-reference-parameter-passing). 148 149Use scenario: 150 151The **Parent** component passes the @State decorated **label** value to the @LocalBuilder function as a function parameter. In this case, the value obtained by the @LocalBuilder function is a common variable value. Therefore, when the @State decorated **label** value is changed, the value in the @LocalBuilder function does not change. 152 153 154```ts 155@Entry 156@Component 157struct Parent { 158 @State label: string = 'Hello'; 159 160 @LocalBuilder 161 citeLocalBuilder(paramA1: string) { 162 Row() { 163 Text(`UseStateVarByValue: ${paramA1} `) 164 } 165 } 166 167 build() { 168 Column() { 169 this.citeLocalBuilder(this.label); 170 } 171 } 172} 173``` 174 175## Differences Between @LocalBuilder and @Builder 176 177When the **componentBuilder** function is decorated by **@Builder**, the **Child** component is displayed. When the **componentBuilder** function is decorated by @LocalBuild, **Parent** component is displayed. 178 179**NOTE** 180 181**componentBuilder()** of the @Builder is passed to **customBuilderParam** of the @BuilderParam child component in the form of **this.componentBuilder**. **this** points to the label of **Child**, that is, **Child** is displayed. 182 183**componentBuilder()** of the @Builder is passed to **customBuilderParam** of the @BuilderParam child component in the form of **this.componentBuilder**. **this** points to the label of **Parent**, that is, **Parent** is displayed. 184 185```ts 186@Component 187struct Child { 188 label: string = `Child`; 189 @BuilderParam customBuilderParam: () => void; 190 191 build() { 192 Column() { 193 this.customBuilderParam() 194 } 195 } 196} 197 198@Entry 199@Component 200struct Parent { 201 label: string = `Parent`; 202 203 @Builder componentBuilder() { 204 Text(`${this.label}`) 205 } 206 207 // @LocalBuilder componentBuilder() { 208 // Text(`${this.label}`) 209 // } 210 211 build() { 212 Column() { 213 Child({ customBuilderParam: this.componentBuilder }) 214 } 215 } 216} 217``` 218 219## Use Scenarios 220 221### Using @LocalBuilder in @ComponentV2 Decorated Custom Components 222 223Call the @LocalBuilder in the custom component decorated by @ComponentV2 to change the variables, triggering the UI re-renders. 224 225```ts 226@ObservedV2 227class Info { 228 @Trace name: string = ''; 229 @Trace age: number = 0; 230} 231 232@ComponentV2 233struct ChildPage { 234 @Require @Param childInfo: Info; 235 build() { 236 Column() { 237 Text(`Custom component name :${this.childInfo.name}`) 238 .fontSize(20) 239 .fontWeight(FontWeight.Bold) 240 Text(`Custom component age :${this.childInfo.age}`) 241 .fontSize(20) 242 .fontWeight(FontWeight.Bold) 243 } 244 } 245} 246 247@Entry 248@ComponentV2 249struct ParentPage { 250 info1: Info = { name: "Tom", age: 25 }; 251 @Local info2: Info = { name: "Tom", age: 25 }; 252 253 @LocalBuilder 254 privateBuilder() { 255 Column() { 256 Text(`LocalBuilder@Builder name :${this.info1.name}`) 257 .fontSize(20) 258 .fontWeight(FontWeight.Bold) 259 Text(`LocalBuilder@Builder age :${this.info1.age}`) 260 .fontSize(20) 261 .fontWeight(FontWeight.Bold) 262 } 263 } 264 265 @LocalBuilder 266 privateBuilderSecond() { 267 Column() { 268 Text(`LocalBuilder@Builder name :${this.info2.name}`) 269 .fontSize(20) 270 .fontWeight(FontWeight.Bold) 271 Text(`LocalBuilder@Builder age :${this.info2.age}`) 272 .fontSize(20) 273 .fontWeight(FontWeight.Bold) 274 } 275 } 276 build() { 277 Column() { 278 Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1 279 .fontSize(30) 280 .fontWeight(FontWeight.Bold) 281 this.privateBuilder() // Call the local @Builder. 282 Line() 283 .width('100%') 284 .height(10) 285 .backgroundColor('#000000').margin(10) 286 Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text1 287 .fontSize(30) 288 .fontWeight(FontWeight.Bold) 289 this.privateBuilderSecond() // Call the local @Builder. 290 Line() 291 .width('100%') 292 .height(10) 293 .backgroundColor('#000000').margin(10) 294 Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1 295 .fontSize(30) 296 .fontWeight(FontWeight.Bold) 297 ChildPage({childInfo: this.info1}) // Call the custom component. 298 Line() 299 .width('100%') 300 .height(10) 301 .backgroundColor('#000000').margin(10) 302 Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text2 303 .fontSize(30) 304 .fontWeight(FontWeight.Bold) 305 ChildPage({childInfo: this.info2}) // Call the custom component. 306 Line() 307 .width('100%') 308 .height(10) 309 .backgroundColor('#000000').margin(10) 310 Button("change info1&info2") 311 .onClick(() => { 312 this.info1 = { name: "Cat", age: 18} // Text1 is not re-rendered because no decorator is used to listen for value changes. 313 this.info2 = { name: "Cat", age: 18} // Text2 is re-rendered because a decorator is used to listen for value changes. 314 }) 315 } 316 } 317} 318``` 319