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