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