270 lines
8.0 KiB
Markdown
270 lines
8.0 KiB
Markdown
```python exec
|
|
import reflex as rx
|
|
|
|
from pcweb.pages.docs import vars, library
|
|
```
|
|
|
|
# Conditional Rendering
|
|
|
|
We use the `cond` component to conditionally render components. The `cond` component acts in a similar way to a conditional (ternary) operator in python, acting in a similar fashion to an `if-else` statement.
|
|
|
|
```md alert
|
|
Check out the API reference for [cond docs]({library.layout.cond.path}).
|
|
```
|
|
|
|
```python eval
|
|
rx.box(height="2em")
|
|
```
|
|
|
|
Here is a simple example to show how by checking the value of the state var `show` we can render either `blue` text or `red` text.
|
|
|
|
The first argument to the `cond` component is the condition we are checking. Here the condition is the value of the state var boolean `show`.
|
|
|
|
If `show` is `True` then the 2nd argument to the `cond` component is rendered, in this case that is `rx.text("Text 1", color="blue")`.
|
|
|
|
If `show` is `False` then the 3rd argument to the `cond` component is rendered, in this case that is `rx.text("Text 2", color="red")`.
|
|
|
|
```python demo exec
|
|
class CondSimpleState(rx.State):
|
|
show: bool = True
|
|
|
|
def change(self):
|
|
self.show = not (self.show)
|
|
|
|
|
|
def cond_simple_example():
|
|
return rx.vstack(
|
|
rx.button("Toggle", on_click=CondSimpleState.change),
|
|
rx.cond(
|
|
CondSimpleState.show,
|
|
rx.text("Text 1", color="blue"),
|
|
rx.text("Text 2", color="red"),
|
|
),
|
|
)
|
|
```
|
|
|
|
## Var Operations (negation)
|
|
|
|
You can use var operations with the `cond` component. To learn more generally about var operators check out [these docs]({vars.var_operations.path}). The logical operator `~` can be used to negate a condition. In this example we show that by negating the condition `~CondNegativeState.show` within the cond, we then render the `rx.text("Text 1", color="blue")` component when the state var `show` is negative.
|
|
|
|
```python demo exec
|
|
class CondNegativeState(rx.State):
|
|
show: bool = True
|
|
|
|
def change(self):
|
|
self.show = not (self.show)
|
|
|
|
|
|
def cond_negative_example():
|
|
return rx.vstack(
|
|
rx.text(f"Value of state var show: {CondNegativeState.show}"),
|
|
rx.button("Toggle", on_click=CondNegativeState.change),
|
|
rx.cond(
|
|
CondNegativeState.show,
|
|
rx.text("Text 1", color="blue"),
|
|
rx.text("Text 2", color="red"),
|
|
),
|
|
rx.cond(
|
|
~CondNegativeState.show,
|
|
rx.text("Text 1", color="blue"),
|
|
rx.text("Text 2", color="red"),
|
|
),
|
|
)
|
|
```
|
|
|
|
## Multiple Conditions
|
|
|
|
It is also possible to make up complex conditions using the `logical or` (|) and `logical and` (&) operators.
|
|
|
|
Here we have an example using the var operators `>=`, `<=`, `&`. We define a condition that if a person has an age between 18 and 65, including those ages, they are able to work, otherwise they cannot.
|
|
|
|
We could equally use the operator `|` to represent a `logical or` in one of our conditions.
|
|
|
|
```python demo exec
|
|
import random
|
|
|
|
class CondComplexState(rx.State):
|
|
age: int = 19
|
|
|
|
def change(self):
|
|
self.age = random.randint(0, 100)
|
|
|
|
|
|
def cond_complex_example():
|
|
return rx.vstack(
|
|
rx.button("Toggle", on_click=CondComplexState.change),
|
|
rx.text(f"Age: {CondComplexState.age}"),
|
|
rx.cond(
|
|
(CondComplexState.age >= 18) & (CondComplexState.age <=65),
|
|
rx.text("You can work!", color="green"),
|
|
rx.text("You cannot work!", color="red"),
|
|
),
|
|
)
|
|
|
|
```
|
|
|
|
## Reusing Cond
|
|
|
|
We can also reuse a `cond` component several times by defining it within a function that returns a `cond`.
|
|
|
|
In this example we define the function `render_item`. This function takes in an `item`, uses the `cond` to check if the item `is_packed`. If it is packed it returns the `item_name` with a `✔` next to it, and if not then it just returns the `item_name`.
|
|
|
|
```python demo exec
|
|
class ToDoListItem(rx.Base):
|
|
item_name: str
|
|
is_packed: bool
|
|
|
|
class CondRepeatState(rx.State):
|
|
to_do_list: list[ToDoListItem] = [
|
|
ToDoListItem(item_name="Space suit", is_packed=True),
|
|
ToDoListItem(item_name="Helmet", is_packed=True),
|
|
ToDoListItem(item_name="Back Pack", is_packed=False),
|
|
]
|
|
|
|
|
|
def render_item(item: [str, bool]):
|
|
return rx.cond(
|
|
item.is_packed,
|
|
rx.chakra.list_item(item.item_name + ' ✔'),
|
|
rx.chakra.list_item(item.item_name),
|
|
)
|
|
|
|
def packing_list():
|
|
return rx.vstack(
|
|
rx.text("Sammy's Packing List"),
|
|
rx.chakra.list(rx.foreach(CondRepeatState.to_do_list, render_item)),
|
|
)
|
|
|
|
```
|
|
|
|
## Nested Conditional
|
|
|
|
We can also nest `cond` components within each other to create more complex logic. In python we can have an `if` statement that then has several `elif` statements before finishing with an `else`. This is also possible in reflex using nested `cond` components. In this example we check whether a number is positive, negative or zero.
|
|
|
|
Here is the python logic using `if` statements:
|
|
|
|
```python
|
|
number = 0
|
|
|
|
if number > 0:
|
|
print("Positive number")
|
|
|
|
elif number == 0:
|
|
print('Zero')
|
|
else:
|
|
print('Negative number')
|
|
```
|
|
|
|
This reflex code that is logically identical:
|
|
|
|
```python demo exec
|
|
import random
|
|
|
|
|
|
class NestedState(rx.State):
|
|
|
|
num: int = 0
|
|
|
|
def change(self):
|
|
self.num = random.randint(-10, 10)
|
|
|
|
|
|
def cond_nested_example():
|
|
return rx.vstack(
|
|
rx.button("Toggle", on_click=NestedState.change),
|
|
rx.cond(
|
|
NestedState.num > 0,
|
|
rx.text(f"{NestedState.num} is Positive!", color="orange"),
|
|
rx.cond(
|
|
NestedState.num == 0,
|
|
rx.text(f"{NestedState.num} is Zero!", color="blue"),
|
|
rx.text(f"{NestedState.num} is Negative!", color="red"),
|
|
)
|
|
),
|
|
)
|
|
|
|
```
|
|
|
|
Here is a more advanced example where we have three numbers and we are checking which of the three is the largest. If any two of them are equal then we return that `Some of the numbers are equal!`.
|
|
|
|
The reflex code that follows is logically identical to doing the following in python:
|
|
|
|
```python
|
|
a = 8
|
|
b = 10
|
|
c = 2
|
|
|
|
if((a>b and a>c) and (a != b and a != c)):
|
|
print(a, " is the largest!")
|
|
elif((b>a and b>c) and (b != a and b != c)):
|
|
print(b, " is the largest!")
|
|
elif((c>a and c>b) and (c != a and c != b)):
|
|
print(c, " is the largest!")
|
|
else:
|
|
print("Some of the numbers are equal!")
|
|
```
|
|
|
|
```python demo exec
|
|
import random
|
|
|
|
|
|
class CNS(rx.State):
|
|
# CNS: CondNestedState
|
|
a: int = 8
|
|
b: int = 10
|
|
c: int = 2
|
|
|
|
|
|
def change(self):
|
|
self.a = random.randint(0, 10)
|
|
self.b = random.randint(0, 10)
|
|
self.c = random.randint(0, 10)
|
|
|
|
|
|
def cond_nested_example_2():
|
|
return rx.vstack(
|
|
rx.button("Toggle", on_click=CNS.change),
|
|
rx.text(f"a: {CNS.a}, b: {CNS.b}, c: {CNS.c}"),
|
|
rx.cond(
|
|
((CNS.a > CNS.b) & (CNS.a > CNS.c)) & ((CNS.a != CNS.b) & (CNS.a != CNS.c)),
|
|
rx.text(f"{CNS.a} is the largest!", color="green"),
|
|
rx.cond(
|
|
((CNS.b > CNS.a) & (CNS.b > CNS.c)) & ((CNS.b != CNS.a) & (CNS.b != CNS.c)),
|
|
rx.text(f"{CNS.b} is the largest!", color="orange"),
|
|
rx.cond(
|
|
((CNS.c > CNS.a) & (CNS.c > CNS.b)) & ((CNS.c != CNS.a) & (CNS.c != CNS.b)),
|
|
rx.text(f"{CNS.c} is the largest!", color="blue"),
|
|
rx.text("Some of the numbers are equal!", color="red"),
|
|
),
|
|
),
|
|
),
|
|
)
|
|
|
|
```
|
|
|
|
## Cond used as a style prop
|
|
|
|
`Cond` can also be used to show and hide content in your reflex app. In this example, we have no third argument to the `cond` operator which means that nothing is rendered if the condition is false.
|
|
|
|
```python demo exec
|
|
class CondStyleState(rx.State):
|
|
show: bool = False
|
|
img_url: str = "/preview.png"
|
|
def change(self):
|
|
self.show = not (self.show)
|
|
|
|
|
|
def cond_style_example():
|
|
return rx.vstack(
|
|
rx.button("Toggle", on_click=CondStyleState.change),
|
|
rx.cond(
|
|
CondStyleState.show,
|
|
rx.image(
|
|
src=CondStyleState.img_url,
|
|
height="25em",
|
|
width="25em",
|
|
),
|
|
),
|
|
)
|
|
```
|