1e41f4b71Sopenharmony_ci# Creating a Custom Component
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ciIn ArkUI, components are what's displayed on the UI. They can be classified as built-in components – those directly provided by the ArkUI framework, and custom components – those defined by developers. Defining the entire application UI with just built-in components would lead to a monolithic design, low code maintainability, and poor execution performance. A good UI is the result of a well-thought-out development process, with such factors as code reusability, separation of service logic from the UI, and version evolution carefully considered. Creating custom components that encapsulate the UI and some business logic is a critical step in this process.
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciThe custom component has the following features:
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ci- Combinable: allows you to combine built-in components and other components, as well as their attributes and methods.
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ci- Reusable: can be reused by other components and used as different instances in different parent components or containers.
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ci- Data-driven update: holds some state and triggers UI re-rendering with the change of state variables.
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ci## Basic Usage of Custom Components
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ciThe following example shows the basic usage of a custom component.
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci```ts
21e41f4b71Sopenharmony_ci@Component
22e41f4b71Sopenharmony_cistruct HelloComponent {
23e41f4b71Sopenharmony_ci  @State message: string = 'Hello, World!';
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ci  build() {
26e41f4b71Sopenharmony_ci    // The HelloComponent custom component combines the <Row> and <Text> built-in components.
27e41f4b71Sopenharmony_ci    Row() {
28e41f4b71Sopenharmony_ci      Text(this.message)
29e41f4b71Sopenharmony_ci        .onClick(() => {
30e41f4b71Sopenharmony_ci          // The change of the state variable message drives the UI to be re-rendered. As a result, the text changes from "Hello, World!" to "Hello, ArkUI!".
31e41f4b71Sopenharmony_ci          this.message = 'Hello, ArkUI!';
32e41f4b71Sopenharmony_ci        })
33e41f4b71Sopenharmony_ci    }
34e41f4b71Sopenharmony_ci  }
35e41f4b71Sopenharmony_ci}
36e41f4b71Sopenharmony_ci```
37e41f4b71Sopenharmony_ci> **NOTE**
38e41f4b71Sopenharmony_ci>
39e41f4b71Sopenharmony_ci> To reference the custom component in another file, use the keyword **export** to export the component and then use **import** to import it to the target file.
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ciMultiple **HelloComponent** instances can be created in the **build()** function of other custom components. In this way, **HelloComponent** is reused by those custom components.
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci```ts
44e41f4b71Sopenharmony_ciclass HelloComponentParam {
45e41f4b71Sopenharmony_ci  message: string = ""
46e41f4b71Sopenharmony_ci}
47e41f4b71Sopenharmony_ci
48e41f4b71Sopenharmony_ci@Entry
49e41f4b71Sopenharmony_ci@Component
50e41f4b71Sopenharmony_cistruct ParentComponent {
51e41f4b71Sopenharmony_ci  param: HelloComponentParam = {
52e41f4b71Sopenharmony_ci    message: 'Hello, World!'
53e41f4b71Sopenharmony_ci  }
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci  build() {
56e41f4b71Sopenharmony_ci    Column() {
57e41f4b71Sopenharmony_ci      Text('ArkUI message')
58e41f4b71Sopenharmony_ci      HelloComponent(this.param);
59e41f4b71Sopenharmony_ci      Divider()
60e41f4b71Sopenharmony_ci      HelloComponent(this.param);
61e41f4b71Sopenharmony_ci    }
62e41f4b71Sopenharmony_ci  }
63e41f4b71Sopenharmony_ci}
64e41f4b71Sopenharmony_ci```
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_ciTo fully understand the preceding example, a knowledge of the following concepts is essential:
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ci- [Basic Structure of a Custom Component](#basic-structure-of-a-custom-component)
71e41f4b71Sopenharmony_ci
72e41f4b71Sopenharmony_ci- [Member Functions/Variables](#member-functionsvariables)
73e41f4b71Sopenharmony_ci
74e41f4b71Sopenharmony_ci- [Rules for Custom Component Parameters](#rules-for-custom-component-parameters)
75e41f4b71Sopenharmony_ci
76e41f4b71Sopenharmony_ci- [build Function](#build-function)
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ci- [Universal Style of a Custom Component](#universal-style-of-a-custom-component)
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci
81e41f4b71Sopenharmony_ci## Basic Structure of a Custom Component
82e41f4b71Sopenharmony_ci
83e41f4b71Sopenharmony_ci- struct: The definition of a custom component must start with the \@Component struct followed by the component name, and then component body enclosed by curly brackets {....}. No inheritance is allowed. You can omit the **new** operator when instantiating a struct.
84e41f4b71Sopenharmony_ci  > **NOTE**
85e41f4b71Sopenharmony_ci  >
86e41f4b71Sopenharmony_ci  > The name or its class or function name of a custom component must be different from that of any built-in components.
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ci- \@Component: The \@Component decorator can decorate only the structs declared by the **struct** keyword. When being decorated by \@Component, a struct has the componentization capability. You must implement the **build** function for it to describe the UI. Each struct can be decorated by only one \@Component. \@Component can accept an optional parameter of the Boolean type.
89e41f4b71Sopenharmony_ci  > **NOTE**
90e41f4b71Sopenharmony_ci  >
91e41f4b71Sopenharmony_ci  > This decorator can be used in ArkTS widgets since API version 9.
92e41f4b71Sopenharmony_ci  > 
93e41f4b71Sopenharmony_ci  > An optional parameter of the Boolean type can be used in the \@Component since API version 11.
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ci  ```ts
96e41f4b71Sopenharmony_ci  @Component
97e41f4b71Sopenharmony_ci  struct MyComponent {
98e41f4b71Sopenharmony_ci  }
99e41f4b71Sopenharmony_ci  ```
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_ci  ### freezeWhenInactive<sup>11+</sup>
102e41f4b71Sopenharmony_ci  Describes the [custom component freezing](arkts-custom-components-freeze.md) option.
103e41f4b71Sopenharmony_ci
104e41f4b71Sopenharmony_ci  | Name  | Type  | Mandatory| Description                                                        |
105e41f4b71Sopenharmony_ci  | ------ | ------ | ---- | ------------------------------------------------------------ |
106e41f4b71Sopenharmony_ci  | freezeWhenInactive | bool | No| Whether to enable the component freezing.|
107e41f4b71Sopenharmony_ci
108e41f4b71Sopenharmony_ci  ```ts
109e41f4b71Sopenharmony_ci  @Component({ freezeWhenInactive: true })
110e41f4b71Sopenharmony_ci  struct MyComponent {
111e41f4b71Sopenharmony_ci  }
112e41f4b71Sopenharmony_ci  ```
113e41f4b71Sopenharmony_ci
114e41f4b71Sopenharmony_ci- build(): The **build()** function is used to define the declarative UI description of a custom component. Every custom component must define a **build()** function. 
115e41f4b71Sopenharmony_ci
116e41f4b71Sopenharmony_ci  ```ts
117e41f4b71Sopenharmony_ci  @Component
118e41f4b71Sopenharmony_ci  struct MyComponent {
119e41f4b71Sopenharmony_ci    build() {
120e41f4b71Sopenharmony_ci    }
121e41f4b71Sopenharmony_ci  }
122e41f4b71Sopenharmony_ci  ```
123e41f4b71Sopenharmony_ci
124e41f4b71Sopenharmony_ci- \@Entry: A custom component decorated with \@Entry is used as the default entry component of the page. Only one component can be decorated with \@Entry in a single page. The \@Entry decorator accepts an optional parameter of type [LocalStorage](arkts-localstorage.md).
125e41f4b71Sopenharmony_ci
126e41f4b71Sopenharmony_ci  > **NOTE**
127e41f4b71Sopenharmony_ci  >
128e41f4b71Sopenharmony_ci  > This decorator can be used in ArkTS widgets since API version 9.
129e41f4b71Sopenharmony_ci  >
130e41f4b71Sopenharmony_ci  > Since API version 10, the \@Entry decorator accepts an optional parameter of type [LocalStorage](arkts-localstorage.md) or type [EntryOptions](#entryOptions).
131e41f4b71Sopenharmony_ci  >
132e41f4b71Sopenharmony_ci  > This decorator can be used in atomic services since API version 11.
133e41f4b71Sopenharmony_ci
134e41f4b71Sopenharmony_ci  ```ts
135e41f4b71Sopenharmony_ci  @Entry
136e41f4b71Sopenharmony_ci  @Component
137e41f4b71Sopenharmony_ci  struct MyComponent {
138e41f4b71Sopenharmony_ci  }
139e41f4b71Sopenharmony_ci  ```
140e41f4b71Sopenharmony_ci
141e41f4b71Sopenharmony_ci  ### EntryOptions<sup>10+</sup>
142e41f4b71Sopenharmony_ci
143e41f4b71Sopenharmony_ci  Describes the named route options.
144e41f4b71Sopenharmony_ci
145e41f4b71Sopenharmony_ci  | Name  | Type  | Mandatory| Description                                                        |
146e41f4b71Sopenharmony_ci  | ------ | ------ | ---- | ------------------------------------------------------------ |
147e41f4b71Sopenharmony_ci  | routeName | string | No| Name of the target named route.|
148e41f4b71Sopenharmony_ci  | storage | [LocalStorage](arkts-localstorage.md) | No| Storage of the page-level UI state.|
149e41f4b71Sopenharmony_ci  | useSharedStorage<sup>12+</sup> | boolean | No| Whether to use the [LocalStorage](arkts-localstorage.md) object returned by the **LocalStorage.getShared()** API.<br>Default value: **false**|
150e41f4b71Sopenharmony_ci
151e41f4b71Sopenharmony_ci  > **NOTE**
152e41f4b71Sopenharmony_ci  >
153e41f4b71Sopenharmony_ci  > When **useSharedStorage** is set to **true** and **storage** is assigned a value, the value of **useSharedStorage** has a higher priority.
154e41f4b71Sopenharmony_ci
155e41f4b71Sopenharmony_ci  ```ts
156e41f4b71Sopenharmony_ci  @Entry({ routeName : 'myPage' })
157e41f4b71Sopenharmony_ci  @Component
158e41f4b71Sopenharmony_ci  struct MyComponent {
159e41f4b71Sopenharmony_ci  }
160e41f4b71Sopenharmony_ci  ```
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci
163e41f4b71Sopenharmony_ci- \@Reusable: Custom components decorated by \@Reusable can be reused.
164e41f4b71Sopenharmony_ci
165e41f4b71Sopenharmony_ci  > **NOTE**
166e41f4b71Sopenharmony_ci  >
167e41f4b71Sopenharmony_ci  > This decorator can be used in ArkTS widgets since API version 10.
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci  ```ts
170e41f4b71Sopenharmony_ci  @Reusable
171e41f4b71Sopenharmony_ci  @Component
172e41f4b71Sopenharmony_ci  struct MyComponent {
173e41f4b71Sopenharmony_ci  }
174e41f4b71Sopenharmony_ci  ```
175e41f4b71Sopenharmony_ci
176e41f4b71Sopenharmony_ci
177e41f4b71Sopenharmony_ci## Member Functions/Variables
178e41f4b71Sopenharmony_ci
179e41f4b71Sopenharmony_ciIn addition to the mandatory **build()** function, a custom component may implement other member functions with the following restrictions:
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ci
182e41f4b71Sopenharmony_ci- Access to the member functions is private. Avoid declaring the member functions as static functions.
183e41f4b71Sopenharmony_ci
184e41f4b71Sopenharmony_ci
185e41f4b71Sopenharmony_ciA custom component can also implement member variables with the following restrictions:
186e41f4b71Sopenharmony_ci
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ci- Access to the member variables is private. Avoid declaring the member variables as static variables.
189e41f4b71Sopenharmony_ci
190e41f4b71Sopenharmony_ci- Local initialization is optional for some member variables and mandatory for others. For details about whether local initialization or initialization from the parent component is required, see [State Management](arkts-state-management-overview.md).
191e41f4b71Sopenharmony_ci
192e41f4b71Sopenharmony_ci
193e41f4b71Sopenharmony_ci## Rules for Custom Component Parameters
194e41f4b71Sopenharmony_ci
195e41f4b71Sopenharmony_ciAs can be learnt from preceding examples, a custom component can be created from a **build** method. During the creation, the custom component's parameters are initialized based on the decorator rules.
196e41f4b71Sopenharmony_ci
197e41f4b71Sopenharmony_ci
198e41f4b71Sopenharmony_ci```ts
199e41f4b71Sopenharmony_ci@Component
200e41f4b71Sopenharmony_cistruct MyComponent {
201e41f4b71Sopenharmony_ci  private countDownFrom: number = 0;
202e41f4b71Sopenharmony_ci  private color: Color = Color.Blue;
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ci  build() {
205e41f4b71Sopenharmony_ci  }
206e41f4b71Sopenharmony_ci}
207e41f4b71Sopenharmony_ci
208e41f4b71Sopenharmony_ci@Entry
209e41f4b71Sopenharmony_ci@Component
210e41f4b71Sopenharmony_cistruct ParentComponent {
211e41f4b71Sopenharmony_ci  private someColor: Color = Color.Pink;
212e41f4b71Sopenharmony_ci
213e41f4b71Sopenharmony_ci  build() {
214e41f4b71Sopenharmony_ci    Column() {
215e41f4b71Sopenharmony_ci      // Create an instance of MyComponent and initialize its countDownFrom variable with the value 10 and its color variable with the value this.someColor.
216e41f4b71Sopenharmony_ci      MyComponent({ countDownFrom: 10, color: this.someColor })
217e41f4b71Sopenharmony_ci    }
218e41f4b71Sopenharmony_ci  }
219e41f4b71Sopenharmony_ci}
220e41f4b71Sopenharmony_ci```
221e41f4b71Sopenharmony_ci
222e41f4b71Sopenharmony_ciIn the following example, a function in the parent component is passed to the child component and called therein.
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ci```ts
225e41f4b71Sopenharmony_ci@Entry
226e41f4b71Sopenharmony_ci@Component
227e41f4b71Sopenharmony_cistruct Parent {
228e41f4b71Sopenharmony_ci  @State cnt: number = 0
229e41f4b71Sopenharmony_ci  submit: () => void = () => {
230e41f4b71Sopenharmony_ci    this.cnt++;
231e41f4b71Sopenharmony_ci  }
232e41f4b71Sopenharmony_ci
233e41f4b71Sopenharmony_ci  build() {
234e41f4b71Sopenharmony_ci    Column() {
235e41f4b71Sopenharmony_ci      Text(`${this.cnt}`)
236e41f4b71Sopenharmony_ci      Son({ submitArrow: this.submit })
237e41f4b71Sopenharmony_ci    }
238e41f4b71Sopenharmony_ci  }
239e41f4b71Sopenharmony_ci}
240e41f4b71Sopenharmony_ci
241e41f4b71Sopenharmony_ci@Component
242e41f4b71Sopenharmony_cistruct Son {
243e41f4b71Sopenharmony_ci  submitArrow?: () => void
244e41f4b71Sopenharmony_ci
245e41f4b71Sopenharmony_ci  build() {
246e41f4b71Sopenharmony_ci    Row() {
247e41f4b71Sopenharmony_ci      Button('add')
248e41f4b71Sopenharmony_ci        .width(80)
249e41f4b71Sopenharmony_ci        .onClick(() => {
250e41f4b71Sopenharmony_ci          if (this.submitArrow) {
251e41f4b71Sopenharmony_ci            this.submitArrow()
252e41f4b71Sopenharmony_ci          }
253e41f4b71Sopenharmony_ci        })
254e41f4b71Sopenharmony_ci    }
255e41f4b71Sopenharmony_ci    .justifyContent(FlexAlign.SpaceBetween)
256e41f4b71Sopenharmony_ci    .height(56)
257e41f4b71Sopenharmony_ci  }
258e41f4b71Sopenharmony_ci}
259e41f4b71Sopenharmony_ci```
260e41f4b71Sopenharmony_ci
261e41f4b71Sopenharmony_ci## build() Function
262e41f4b71Sopenharmony_ci
263e41f4b71Sopenharmony_ciWhatever declared in the **build()** function are called UI descriptions. UI descriptions must comply with the following rules:
264e41f4b71Sopenharmony_ci
265e41f4b71Sopenharmony_ci- For an \@Entry decorated custom component, exactly one root component is required under the **build()** function. This root component must be a container component. **ForEach** is not allowed at the top level.
266e41f4b71Sopenharmony_ci  For an \@Component decorated custom component, exactly one root component is required under the **build()** function. This root component is not necessarily a container component. **ForEach** is not allowed at the top level.
267e41f4b71Sopenharmony_ci
268e41f4b71Sopenharmony_ci  ```ts
269e41f4b71Sopenharmony_ci  @Entry
270e41f4b71Sopenharmony_ci  @Component
271e41f4b71Sopenharmony_ci  struct MyComponent {
272e41f4b71Sopenharmony_ci    build() {
273e41f4b71Sopenharmony_ci      // Exactly one root component is required, and it must be a container component.
274e41f4b71Sopenharmony_ci      Row() {
275e41f4b71Sopenharmony_ci        ChildComponent() 
276e41f4b71Sopenharmony_ci      }
277e41f4b71Sopenharmony_ci    }
278e41f4b71Sopenharmony_ci  }
279e41f4b71Sopenharmony_ci  
280e41f4b71Sopenharmony_ci  @Component
281e41f4b71Sopenharmony_ci  struct ChildComponent {
282e41f4b71Sopenharmony_ci    build() {
283e41f4b71Sopenharmony_ci      // Exactly one root component is required, and it is not necessarily a container component.
284e41f4b71Sopenharmony_ci      Image('test.jpg')
285e41f4b71Sopenharmony_ci    }
286e41f4b71Sopenharmony_ci  }
287e41f4b71Sopenharmony_ci  ```
288e41f4b71Sopenharmony_ci
289e41f4b71Sopenharmony_ci- Local variable declaration is not allowed. The following example should be avoided:
290e41f4b71Sopenharmony_ci
291e41f4b71Sopenharmony_ci  ```ts
292e41f4b71Sopenharmony_ci  build() {
293e41f4b71Sopenharmony_ci    // Avoid: declaring a local variable.
294e41f4b71Sopenharmony_ci    let a: number = 1;
295e41f4b71Sopenharmony_ci  }
296e41f4b71Sopenharmony_ci  ```
297e41f4b71Sopenharmony_ci
298e41f4b71Sopenharmony_ci- **console.info** can be used in the UI description only when it is in a method or function. The following example should be avoided:
299e41f4b71Sopenharmony_ci
300e41f4b71Sopenharmony_ci  ```ts
301e41f4b71Sopenharmony_ci  build() {
302e41f4b71Sopenharmony_ci    // Avoid: using console.info directly in UI description.
303e41f4b71Sopenharmony_ci    console.info('print debug log');
304e41f4b71Sopenharmony_ci  }
305e41f4b71Sopenharmony_ci  ```
306e41f4b71Sopenharmony_ci
307e41f4b71Sopenharmony_ci- Creation of a local scope is not allowed. The following example should be avoided:
308e41f4b71Sopenharmony_ci
309e41f4b71Sopenharmony_ci  ```ts
310e41f4b71Sopenharmony_ci  build() {
311e41f4b71Sopenharmony_ci    // Avoid: creating a local scope.
312e41f4b71Sopenharmony_ci    {
313e41f4b71Sopenharmony_ci      ...
314e41f4b71Sopenharmony_ci    }
315e41f4b71Sopenharmony_ci  }
316e41f4b71Sopenharmony_ci  ```
317e41f4b71Sopenharmony_ci
318e41f4b71Sopenharmony_ci- Only methods decorated by \@Builder can be called. The parameters of built-in components can be the return values of TS methods.
319e41f4b71Sopenharmony_ci
320e41f4b71Sopenharmony_ci  ```ts
321e41f4b71Sopenharmony_ci  @Component
322e41f4b71Sopenharmony_ci  struct ParentComponent {
323e41f4b71Sopenharmony_ci    doSomeCalculations() {
324e41f4b71Sopenharmony_ci    }
325e41f4b71Sopenharmony_ci
326e41f4b71Sopenharmony_ci    calcTextValue(): string {
327e41f4b71Sopenharmony_ci      return 'Hello World';
328e41f4b71Sopenharmony_ci    }
329e41f4b71Sopenharmony_ci
330e41f4b71Sopenharmony_ci    @Builder doSomeRender() {
331e41f4b71Sopenharmony_ci      Text(`Hello World`)
332e41f4b71Sopenharmony_ci    }
333e41f4b71Sopenharmony_ci
334e41f4b71Sopenharmony_ci    build() {
335e41f4b71Sopenharmony_ci      Column() {
336e41f4b71Sopenharmony_ci        // Avoid: calling a method not decorated by @Builder.
337e41f4b71Sopenharmony_ci        this.doSomeCalculations();
338e41f4b71Sopenharmony_ci        // Prefer: Call an @Builder decorated method.
339e41f4b71Sopenharmony_ci        this.doSomeRender();
340e41f4b71Sopenharmony_ci        // Prefer: Pass the return value of a TS method as the parameter.
341e41f4b71Sopenharmony_ci        Text(this.calcTextValue())
342e41f4b71Sopenharmony_ci      }
343e41f4b71Sopenharmony_ci    }
344e41f4b71Sopenharmony_ci  }
345e41f4b71Sopenharmony_ci  ```
346e41f4b71Sopenharmony_ci
347e41f4b71Sopenharmony_ci- The **switch** syntax is not allowed. Use **if** instead. The following is an example:
348e41f4b71Sopenharmony_ci
349e41f4b71Sopenharmony_ci  ```ts
350e41f4b71Sopenharmony_ci  build() {
351e41f4b71Sopenharmony_ci    Column() {
352e41f4b71Sopenharmony_ci      // Avoid: using the switch syntax.
353e41f4b71Sopenharmony_ci      switch (expression) {
354e41f4b71Sopenharmony_ci        case 1:
355e41f4b71Sopenharmony_ci          Text('...')
356e41f4b71Sopenharmony_ci          break;
357e41f4b71Sopenharmony_ci        case 2:
358e41f4b71Sopenharmony_ci          Image('...')
359e41f4b71Sopenharmony_ci          break;
360e41f4b71Sopenharmony_ci        default:
361e41f4b71Sopenharmony_ci          Text('...')
362e41f4b71Sopenharmony_ci          break;
363e41f4b71Sopenharmony_ci      }
364e41f4b71Sopenharmony_ci      // Correct usage: Use if.
365e41f4b71Sopenharmony_ci      if(expression == 1) {
366e41f4b71Sopenharmony_ci        Text('...')
367e41f4b71Sopenharmony_ci      } else if(expression == 2) {
368e41f4b71Sopenharmony_ci        Image('...')
369e41f4b71Sopenharmony_ci      } else {
370e41f4b71Sopenharmony_ci        Text('...')
371e41f4b71Sopenharmony_ci      }
372e41f4b71Sopenharmony_ci    }
373e41f4b71Sopenharmony_ci  }
374e41f4b71Sopenharmony_ci  ```
375e41f4b71Sopenharmony_ci
376e41f4b71Sopenharmony_ci- Expressions are not allowed. The following example should be avoided:
377e41f4b71Sopenharmony_ci
378e41f4b71Sopenharmony_ci  ```ts
379e41f4b71Sopenharmony_ci  build() {
380e41f4b71Sopenharmony_ci    Column() {
381e41f4b71Sopenharmony_ci      // Avoid: expressions.
382e41f4b71Sopenharmony_ci      (this.aVar > 10) ? Text('...') : Image('...')
383e41f4b71Sopenharmony_ci    }
384e41f4b71Sopenharmony_ci  }
385e41f4b71Sopenharmony_ci  ```
386e41f4b71Sopenharmony_ci
387e41f4b71Sopenharmony_ci- Directly changing a state variable is not allowed. The following example should be avoided:
388e41f4b71Sopenharmony_ci
389e41f4b71Sopenharmony_ci  ```ts
390e41f4b71Sopenharmony_ci  @Component
391e41f4b71Sopenharmony_ci  struct CompA {
392e41f4b71Sopenharmony_ci    @State col1: Color = Color.Yellow;
393e41f4b71Sopenharmony_ci    @State col2: Color = Color.Green;
394e41f4b71Sopenharmony_ci    @State count: number = 1;
395e41f4b71Sopenharmony_ci    build() {
396e41f4b71Sopenharmony_ci      Column() {
397e41f4b71Sopenharmony_ci        // Avoid: directly changing the value of count in the <Text> component.
398e41f4b71Sopenharmony_ci        Text(`${this.count++}`)
399e41f4b71Sopenharmony_ci          .width(50)
400e41f4b71Sopenharmony_ci          .height(50)
401e41f4b71Sopenharmony_ci          .fontColor(this.col1)
402e41f4b71Sopenharmony_ci          .onClick(() => {
403e41f4b71Sopenharmony_ci            this.col2 = Color.Red;
404e41f4b71Sopenharmony_ci          })
405e41f4b71Sopenharmony_ci        Button("change col1").onClick(() =>{
406e41f4b71Sopenharmony_ci          this.col1 = Color.Pink;
407e41f4b71Sopenharmony_ci        })
408e41f4b71Sopenharmony_ci      }
409e41f4b71Sopenharmony_ci      .backgroundColor(this.col2)
410e41f4b71Sopenharmony_ci    }
411e41f4b71Sopenharmony_ci  }
412e41f4b71Sopenharmony_ci  ```
413e41f4b71Sopenharmony_ci
414e41f4b71Sopenharmony_ci  In ArkUI state management, UI re-render is driven by state.
415e41f4b71Sopenharmony_ci
416e41f4b71Sopenharmony_ci  ![en-us_image_0000001651365257](figures/en-us_image_0000001651365257.png)
417e41f4b71Sopenharmony_ci
418e41f4b71Sopenharmony_ci  Therefore, do not change any state variable in the **build()** or \@Builder decorated method of a custom component. Otherwise, loop rendering may result. Depending on the update mode (full update or minimum update), **Text('${this.count++}')** imposes different effects:
419e41f4b71Sopenharmony_ci
420e41f4b71Sopenharmony_ci  - Full update (API version 8 or before): ArkUI may fall into an infinite re-rendering loop because each rendering of the **Text** component changes the application state and causes a new round of re-renders. When **this.col2** is changed, the entire **build** function is executed. As a result, the text bound to **Text(${this.count++})** is also changed. Each time **Text(${this.count++})** is re-rendered, the **this.count** state variable is updated, and a new round of **build** execution follows, resulting in an infinite loop.
421e41f4b71Sopenharmony_ci  - Minimized update (API version 9 or later): When **this.col2** is changed, only the **Column** component is updated, and the **Text** component is not changed. When **this.col1** is changed, the entire **Text** component is updated and all of its attribute functions are executed. As a result, the value of **${this.count++}** in the **Text** component is changed. Currently, the UI is updated by component. If an attribute of a component changes, the entire component is updated. Therefore, the overall update link is as follows: **this.col1** = **Color.Pink** - > **Text** component re-render - > **this.count++** - > **Text** component re-render. It should be noted that this way of writing causes the **Text** component to be rendered twice during the initial render, which affects the performance.
422e41f4b71Sopenharmony_ci
423e41f4b71Sopenharmony_ci  The behavior of changing the application state in the **build** function may be more covert than that in the preceding example. The following are some examples:
424e41f4b71Sopenharmony_ci
425e41f4b71Sopenharmony_ci  - Changing the state variable within the \@Builder, \@Extend, or \@Styles decorated method
426e41f4b71Sopenharmony_ci
427e41f4b71Sopenharmony_ci  - Changing the application state variable in the function called during parameter calculation, for example, **Text('${this.calcLabel()}')**
428e41f4b71Sopenharmony_ci
429e41f4b71Sopenharmony_ci  - Modifying the current array: In the following code snippet, **sort()** changes the array **this.arr**, and the subsequent **filter** method returns a new array.
430e41f4b71Sopenharmony_ci
431e41f4b71Sopenharmony_ci    ```ts
432e41f4b71Sopenharmony_ci    // Avoid the usage below.
433e41f4b71Sopenharmony_ci    @State arr : Array<...> = [ ... ];
434e41f4b71Sopenharmony_ci    ForEach(this.arr.sort().filter(...), 
435e41f4b71Sopenharmony_ci      item => { 
436e41f4b71Sopenharmony_ci      ...
437e41f4b71Sopenharmony_ci    })
438e41f4b71Sopenharmony_ci    // Prefer: Call filter before sort() to return a new array. In this way, sort() does not change this.arr.
439e41f4b71Sopenharmony_ci    ForEach(this.arr.filter(...).sort(), 
440e41f4b71Sopenharmony_ci      item => { 
441e41f4b71Sopenharmony_ci      ...
442e41f4b71Sopenharmony_ci    })
443e41f4b71Sopenharmony_ci    ```
444e41f4b71Sopenharmony_ci
445e41f4b71Sopenharmony_ci## Universal Style of a Custom Component
446e41f4b71Sopenharmony_ci
447e41f4b71Sopenharmony_ciThe universal style of a custom component is configured by invoking chainable attribute methods.
448e41f4b71Sopenharmony_ci
449e41f4b71Sopenharmony_ci
450e41f4b71Sopenharmony_ci```ts
451e41f4b71Sopenharmony_ci@Component
452e41f4b71Sopenharmony_cistruct MyComponent2 {
453e41f4b71Sopenharmony_ci  build() {
454e41f4b71Sopenharmony_ci    Button(`Hello World`)
455e41f4b71Sopenharmony_ci  }
456e41f4b71Sopenharmony_ci}
457e41f4b71Sopenharmony_ci
458e41f4b71Sopenharmony_ci@Entry
459e41f4b71Sopenharmony_ci@Component
460e41f4b71Sopenharmony_cistruct MyComponent {
461e41f4b71Sopenharmony_ci  build() {
462e41f4b71Sopenharmony_ci    Row() {
463e41f4b71Sopenharmony_ci      MyComponent2()
464e41f4b71Sopenharmony_ci        .width(200)
465e41f4b71Sopenharmony_ci        .height(300)
466e41f4b71Sopenharmony_ci        .backgroundColor(Color.Red)
467e41f4b71Sopenharmony_ci    }
468e41f4b71Sopenharmony_ci  }
469e41f4b71Sopenharmony_ci}
470e41f4b71Sopenharmony_ci```
471e41f4b71Sopenharmony_ci
472e41f4b71Sopenharmony_ci> **NOTE**
473e41f4b71Sopenharmony_ci>
474e41f4b71Sopenharmony_ci> When ArkUI sets styles for custom components, an invisible container component is set for **MyComponent2**. These styles are set on the container component instead of the **Button** component of **MyComponent2**. As seen from the rendering result, the red background color is not directly applied to the button. Instead, it is applied to the container component that is invisible to users where the button is located.
475e41f4b71Sopenharmony_ci
476e41f4b71Sopenharmony_ci<!--no_check-->
477