1# if/else: Conditional Rendering 2 3 4ArkTS provides conditional rendering. Use the **if**, **else**, and **else if** statements to enable your application to display different content based on the condition or state. 5 6> **NOTE** 7> 8> Since API version 9, this API is supported in ArkTS widgets. 9 10## Rules of Use 11 12- The **if**, **else**, and **else if** statements are supported. 13 14- The conditional statements following **if** and **else if** can use state variables. 15 16- Use of the conditional statements within a container component is allowed for building 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 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 created in conditional statements. For example, when a conditional statement is used in the **\<Grid>** container component, whose child components can only be **\<GridItem>**, only the **\<GridItem>** component can be used in the conditional statement. 23 24 25## Update Mechanism 26 27A conditional statement updates whenever a state variable used inside the **if** condition or the **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 framework removes all child components that have been built. 32 333. The framework executes the build function of the 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## Application 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** condition or the **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 State 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 Row() { 97 Text(`${this.label}`) 98 Button(`counter ${this.counter} +1`) 99 .onClick(() => { 100 this.counter += 1; 101 }) 102 } 103 } 104} 105 106@Entry 107@Component 108struct MainView { 109 @State toggle: boolean = true; 110 111 build() { 112 Column() { 113 if (this.toggle) { 114 CounterView({ label: 'CounterView #positive' }) 115 } else { 116 CounterView({ label: 'CounterView #negative' }) 117 } 118 Button(`toggle ${this.toggle}`) 119 .onClick(() => { 120 this.toggle = !this.toggle; 121 }) 122 } 123 } 124} 125``` 126 127On first render, the **CounterView** (label: **'CounterView \#positive'**) child component is created. This child component carries the \@State decorated variable **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 will be removed. At the same time, a new **CounterView** (label: **'CounterView \#negative'**) child component will be created. Its own **counter** state variable is set to the initial value **0**. 128 129> **NOTE** 130> 131> **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 updating of an existing child component and no preservation of state. 132 133The following example shows the required modifications if the value of **counter** be preserved when the **if** condition changes: 134 135 136``` 137@Component 138struct CounterView { 139 @Link counter: number; 140 label: string = 'unknown'; 141 142 build() { 143 Row() { 144 Text(`${this.label}`) 145 Button(`counter ${this.counter} +1`) 146 .onClick(() => { 147 this.counter += 1; 148 }) 149 } 150 } 151} 152 153@Entry 154@Component 155struct MainView { 156 @State toggle: boolean = true; 157 @State counter: number = 0; 158 159 build() { 160 Column() { 161 if (this.toggle) { 162 CounterView({ counter: $counter, label: 'CounterView #positive' }) 163 } else { 164 CounterView({ counter: $counter, label: 'CounterView #negative' }) 165 } 166 Button(`toggle ${this.toggle}`) 167 .onClick(() => { 168 this.toggle = !this.toggle; 169 }) 170 } 171 } 172} 173``` 174 175Here, the \@State decorated variable **counter** is owned by the parent component. Therefore, it is not destroyed when a **CounterView** component instance is removed. The **CounterView** component refers to the state by an \@Link decorator. This technique is sometimes referred to as "pushing up the state in the component tree." 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. 176 177 178### Nested if Statements 179 180The nesting of **if** statements makes no difference to the rule about the parent component. 181 182 183```ts 184@Entry 185@Component 186struct CompA { 187 @State toggle: boolean = false; 188 @State toggleColor: boolean = false; 189 190 build() { 191 Column() { 192 Text('Before') 193 .fontSize(15) 194 if (this.toggle) { 195 Text('Top True, positive 1 top') 196 .backgroundColor('#aaffaa').fontSize(20) 197 // Inner if statement 198 if (this.toggleColor) { 199 Text('Top True, Nested True, positive COLOR Nested ') 200 .backgroundColor('#00aaaa').fontSize(15) 201 } else { 202 Text('Top True, Nested False, Negative COLOR Nested ') 203 .backgroundColor('#aaaaff').fontSize(15) 204 } 205 } else { 206 Text('Top false, negative top level').fontSize(20) 207 .backgroundColor('#ffaaaa') 208 if (this.toggleColor) { 209 Text('positive COLOR Nested ') 210 .backgroundColor('#00aaaa').fontSize(15) 211 } else { 212 Text('Negative COLOR Nested ') 213 .backgroundColor('#aaaaff').fontSize(15) 214 } 215 } 216 Text('After') 217 .fontSize(15) 218 Button('Toggle Outer') 219 .onClick(() => { 220 this.toggle = !this.toggle; 221 }) 222 Button('Toggle Inner') 223 .onClick(() => { 224 this.toggleColor = !this.toggleColor; 225 }) 226 } 227 } 228} 229``` 230