1# if/else: Conditional Rendering
2
3
4ArkTS provides conditional rendering. It supports the use of the **if**, **else**, and **else if** statements to display different content based on the application state.
5
6> **NOTE**
7>
8> This API can be used in ArkTS widgets since API version 9.
9
10## Rules of Use
11
12- The **if**, **else**, and **else if** statements are supported.
13
14- The condition statements following the **if** or **else if** statement can use state variables or normal variables. (Value change of state variables can trigger UI rendering in real time, but value change of normal variables cannot.)
15
16- Conditional statements can be used within a container component to build different child components.
17
18- Conditional statements are "transparent" when it comes to the parent-child relationship of components. Rules about permissible child components must be followed when there is one or more **if** statements between the parent and child components.
19
20- The build function inside each conditional branch must follow the special rules for build functions. Each of such build functions must create one or more components. An empty build function that creates no components will result in a syntax error.
21
22- Some container components impose restrictions on the type or number of child components. When conditional statements are used in such components, these restrictions also apply to the components to be created by using the conditional statements. For example, the child component of the [Grid](../reference/apis-arkui/arkui-ts/ts-container-grid.md) container component supports only the [GridItem](../reference/apis-arkui/arkui-ts/ts-container-griditem.md) component. Therefore, only the **GridItem** can be used in the conditional statement within **Grid**.
23
24
25## Update Mechanism
26
27A conditional statement updates whenever a state variable used inside the **if** or **else if** condition changes. Specifically:
28
291. The conditional statement re-evaluates the conditions. If the evaluation of the conditions changes, steps 2 and 3 are performed. Otherwise, no follow-up operation is required.
30
312. The ArkUI framework removes all child components that have been built.
32
333. The ArkUI framework executes the build function of the conditional branch again to add the generated child component to its parent component. If an applicable **else** branch is missing, no new build function will be executed.
34
35A condition can include Typescript expressions. As for any expression inside build functions, such an expression must not change any application state.
36
37
38## Use Scenarios
39
40
41### Using if for Conditional Rendering
42
43
44```ts
45@Entry
46@Component
47struct ViewA {
48  @State count: number = 0;
49
50  build() {
51    Column() {
52      Text(`count=${this.count}`)
53
54      if (this.count > 0) {
55        Text(`count is positive`)
56          .fontColor(Color.Green)
57      }
58
59      Button('increase count')
60        .onClick(() => {
61          this.count++;
62        })
63
64      Button('decrease count')
65        .onClick(() => {
66          this.count--;
67        })
68    }
69  }
70}
71```
72
73Each branch of the **if** statement includes a build function. Each of such build functions must create one or more components. On initial render, **if** will execute a build function and add the generated child component to its parent component.
74
75**if** updates whenever a state variable used inside the **if** or **else if** condition changes, and re-evaluates the conditions. If the evaluation of the conditions changes, it means that another branch of **if** needs to be built. In this case, the ArkUI framework will:
76
771. Remove all previously rendered components (of the earlier branch).
78
792. Execute the build function of the branch and add the generated child component to its parent component.
80
81In the preceding example, if **count** increases from 0 to 1, then **if** updates, the condition **count > 0** is re-evaluated, and the evaluation result changes from **false** to **true**. Therefore, the positive branch build function will be executed, which creates a **Text** component and adds it to the **Column** parent component. If **count** changes back to 0 later, then the **Text** component will be removed from the **Column** component. Since there is no **else** branch, no new build function will be executed.
82
83
84### if ... else ... and Child Component States
85
86This example involves **if...** **else...** and a child component with an \@State decorated variable.
87
88
89```ts
90@Component
91struct CounterView {
92  @State counter: number = 0;
93  label: string = 'unknown';
94
95  build() {
96    Column({ space: 20 }) {
97      Text(`${this.label}`)
98      Button(`counter ${this.counter} +1`)
99        .onClick(() => {
100          this.counter += 1;
101        })
102    }
103    .margin(10)
104    .padding(10)
105    .border({ width: 1 })
106  }
107}
108
109@Entry
110@Component
111struct MainView {
112  @State toggle: boolean = true;
113
114  build() {
115    Column() {
116      if (this.toggle) {
117        CounterView({ label: 'CounterView #positive' })
118      } else {
119        CounterView({ label: 'CounterView #negative' })
120      }
121      Button(`toggle ${this.toggle}`)
122        .onClick(() => {
123          this.toggle = !this.toggle;
124        })
125    }
126    .width('100%')
127    .justifyContent(FlexAlign.Center)
128  }
129}
130```
131
132On first render, the **CounterView** (label: **'CounterView \#positive'**) child component is created. This child component carries the \@State decorated variable, named **counter**. When the **CounterView.counter** state variable is updated, the **CounterView** (label: **'CounterView \#positive'**) child component is re-rendered, with its state variable value preserved. When the value of the **MainView.toggle** state variable changes to **false**, the **if** statement inside the **MainView** parent component gets updated, and subsequently the **CounterView** (label: **'CounterView \#positive'**) child component is removed. At the same time, a new **CounterView** (label: **'CounterView \#negative'**) child component is created, with the **counter** state variable set to the initial value **0**.
133
134> **NOTE**
135>
136> **CounterView** (label: **'CounterView \#positive'**) and **CounterView** (label: **'CounterView \#negative'**) are two distinct instances of the same custom component. When the **if** branch changes, there is no update to an existing child component or no preservation of state.
137
138The following example shows the required modifications if the value of **counter** needs to be preserved when the **if** condition changes:
139
140
141```ts
142@Component
143struct CounterView {
144  @Link counter: number;
145  label: string = 'unknown';
146
147  build() {
148    Column({ space: 20 }) {
149      Text(`${this.label}`)
150        .fontSize(20)
151      Button(`counter ${this.counter} +1`)
152        .onClick(() => {
153          this.counter += 1;
154        })
155    }
156    .margin(10)
157    .padding(10)
158    .border({ width: 1 })
159  }
160}
161
162@Entry
163@Component
164struct MainView {
165  @State toggle: boolean = true;
166  @State counter: number = 0;
167
168  build() {
169    Column() {
170      if (this.toggle) {
171        CounterView({ counter: $counter, label: 'CounterView #positive' })
172      } else {
173        CounterView({ counter: $counter, label: 'CounterView #negative' })
174      }
175      Button(`toggle ${this.toggle}`)
176        .onClick(() => {
177          this.toggle = !this.toggle;
178        })
179    }
180    .width('100%')
181    .justifyContent(FlexAlign.Center)
182  }
183}
184```
185
186Here, the \@State decorated variable **counter** is owned by the parent component. Therefore, it is not destroyed when a **CounterView** component instance is destroyed. The **CounterView** component refers to the state by an \@Link decorator. The state must be moved from a child to its parent (or parent of parent) to avoid losing it when the conditional content (or repeated content) is destroyed.
187
188
189### Nested if Statements
190
191The nesting of **if** statements makes no difference to the rule about the parent component.
192
193
194```ts
195@Entry
196@Component
197struct CompA {
198  @State toggle: boolean = false;
199  @State toggleColor: boolean = false;
200
201  build() {
202    Column({ space: 20 }) {
203      Text('Before')
204        .fontSize(15)
205      if (this.toggle) {
206        Text('Top True, positive 1 top')
207          .backgroundColor('#aaffaa').fontSize(20)
208        // Inner if statement
209        if (this.toggleColor) {
210          Text('Top True, Nested True, positive COLOR  Nested ')
211            .backgroundColor('#00aaaa').fontSize(15)
212        } else {
213          Text('Top True, Nested False, Negative COLOR  Nested ')
214            .backgroundColor('#aaaaff').fontSize(15)
215        }
216      } else {
217        Text('Top false, negative top level').fontSize(20)
218          .backgroundColor('#ffaaaa')
219        if (this.toggleColor) {
220          Text('positive COLOR  Nested ')
221            .backgroundColor('#00aaaa').fontSize(15)
222        } else {
223          Text('Negative COLOR  Nested ')
224            .backgroundColor('#aaaaff').fontSize(15)
225        }
226      }
227      Text('After')
228        .fontSize(15)
229      Button('Toggle Outer')
230        .onClick(() => {
231          this.toggle = !this.toggle;
232        })
233      Button('Toggle Inner')
234        .onClick(() => {
235          this.toggleColor = !this.toggleColor;
236        })
237    }
238    .width('100%')
239    .justifyContent(FlexAlign.Center)
240  }
241}
242```
243