from typing import List
class WordCycleState(rx.State):
# The words to cycle through.
text: List[str] = ["Welcome", "to", "Reflex", "!"]
# The index of the current word.
index: int = 0
def next_word(self):
self.index = (self.index + 1) % len(self.text)
@rx.var
def get_text(self) -> str:
return self.text[self.index]
def index():
return rx.heading(
WordCycleState.get_text,
on_mouse_over=WordCycleState.next_word,
color="green",
)
on_mouse_over
.next_word
handler will be called to cycle the word. Once the handler returns, the UI will be updated to reflect the new state.from typing import List
class ArgState(rx.State):
colors: List[str] = [
"rgba(222,44,12)",
"white",
"#007ac2",
]
def change_color(self, color: str, index: int):
self.colors[index] = color
def index():
return rx.hstack(
rx.input(
default_value=ArgState.colors[0],
on_blur=lambda c: ArgState.change_color(c, 0),
bg=ArgState.colors[0],
),
rx.input(
default_value=ArgState.colors[1],
on_blur=lambda c: ArgState.change_color(c, 1),
bg=ArgState.colors[1],
),
rx.input(
default_value=ArgState.colors[2],
on_blur=lambda c: ArgState.change_color(c, 2),
bg=ArgState.colors[2],
),
)
change_color
, the color and the index of the color to change.on_blur
event trigger passes the text of the input as an argument to the lambda, and the lambda calls the change_color
event handler with the text and the index of the input.set_VARNAME
.from typing import List
options: List[str] = ["1", "2", "3", "4"]
class SetterState1(rx.State):
selected: str = "1"
def change(self, value):
self.selected = value
def index():
return rx.vstack(
rx.badge(
SetterState1.selected, color_scheme="green"
),
rx.select(
options,
on_change=lambda value: SetterState1.change(
value
),
),
)
from typing import List
options: List[str] = ["1", "2", "3", "4"]
class SetterState2(rx.State):
selected: str = "1"
def index():
return rx.vstack(
rx.badge(
SetterState2.selected, color_scheme="green"
),
rx.select(
options,
on_change=SetterState2.set_selected,
),
)
selected
is set_selected
. Both of these examples are equivalent.StateUpdate
when it has finished running. This works fine for basic event, but sometimes we need more complex logic. To update the UI multiple times in an event handler, we can yield
when we want to send an update.yield
. For every yield inside the function, a StateUpdate
will be sent to the frontend with the changes up to this point in the execution of the event handler.0
import asyncio
class MultiUpdateState(rx.State):
count: int = 0
async def timed_update(self):
for i in range(5):
await asyncio.sleep(0.5)
self.count += 1
yield
def index():
return rx.vstack(
rx.text(MultiUpdateState.count),
rx.button(
"Start", on_click=MultiUpdateState.timed_update
),
)
import asyncio
class ProgressExampleState(rx.State):
count: int = 0
show_progress: bool = False
async def increment(self):
self.show_progress = True
yield
# Think really hard.
await asyncio.sleep(0.5)
self.count += 1
self.show_progress = False
def index():
return rx.cond(
ProgressExampleState.show_progress,
rx.circular_progress(is_indeterminate=True),
rx.heading(
ProgressExampleState.count,
on_click=ProgressExampleState.increment,
_hover={"cursor": "pointer"},
),
)
self.call_handler
syntax to run another event handler. As always, you can yield within your function to send incremental updates to the frontend.class CallHandlerState(rx.State):
count: int = 0
progress: int = 0
async def run(self):
# Reset the count.
self.set_progress(0)
yield
# Count to 10 while showing progress.
for i in range(10):
# Wait and increment.
await asyncio.sleep(0.5)
self.count += 1
# Update the progress.
self.set_progress(i + 1)
# Yield to send the update.
yield
def index():
return rx.vstack(
rx.badge(
CallHandlerState.count,
font_size="1.5em",
color_scheme="green",
),
rx.progress(
value=CallHandlerState.progress,
max_=10,
width="100%",
),
rx.button("Run", on_click=CallHandlerState.run),
)
Be sure to use the class name State
(or any substate) rather than self
when returning events.
class CollatzState(rx.State):
count: int = 0
def start_collatz(self, count: str):
"""Run the collatz conjecture on the given number."""
self.count = abs(int(count))
return CollatzState.run_step
async def run_step(self):
"""Run a single step of the collatz conjecture."""
while self.count > 1:
await asyncio.sleep(0.5)
if self.count % 2 == 0:
# If the number is even, divide by 2.
self.count /= 2
else:
# If the number is odd, multiply by 3 and add 1.
self.count = self.count * 3 + 1
yield
def index():
return rx.vstack(
rx.badge(
CollatzState.count,
font_size="1.5em",
color_scheme="green",
),
rx.input(on_blur=CollatzState.start_collatz),
)
on_blur
event is triggered, the event handler start_collatz
is called. It sets the initial count, then calls run_step
which runs until the count reaches 1
. class ServerSideState2(rx.State):
def alert(self):
return rx.window_alert("Hello World!")
def index():
return rx.button(
"Alert", on_click=ServerSideState2.alert
)