-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Describe the bug
Inside a state class method (an event handler), I try to send some rx.toast components to the UI through yield rx.toast. However, they don't get displayed on the screen when they're expected to be, but instead, they get displayed altogether only when the method finishes its execution.
To Reproduce
On a blank new project, here's my app main script:
import asyncio
from collections.abc import AsyncGenerator
import reflex as rx
class State(rx.State):
loading_data: bool = False
building_plot: bool = False
@rx.event
async def handle_on_load(self) -> AsyncGenerator[rx.Component | None, None, None]:
print(f"Page {self.router.url.path} loaded.")
# load data
self.loading_data = True
yield
await asyncio.sleep(3) # loading data...
self.loading_data = False
yield
yield rx.toast.info("Data loaded, starting plots", duration=10_000, close_button=True)
# build plot
self.building_plot = True
yield
await asyncio.sleep(3) # building plot...
self.building_plot = False
yield
yield rx.toast.info("Finished updating plots", duration=10_000, close_button=True)
def index() -> rx.Component:
return rx.container(
rx.vstack(
rx.heading("Welcome to Reflex!", size="9"),
rx.text(f"Loading data: {State.loading_data}"),
rx.text(f"Building plot: {State.building_plot}"),
spacing="5",
justify="center",
min_height="85vh",
),
)
app = rx.App()
app.add_page(index, on_load=State.handle_on_load)Expected behavior
On the screen, there are two text components to display the current value of the boolean attributes loading_data and building_plot; both are initialized with False. When the page is loaded or refreshed, State.handle_on_load is called and loading_data is set to True; after 3s, it switches to False and simultaneously building_plot becomes True; by this time (i.e. 3s after loading/refreshing the page), I expected a toast to be displayed on the screen, and it doesn't happen. By the end of the method execution (i.e. 6s after loading/refreshing the page), building_plot is set to False again, and the two toasts are finally displayed on the screen altogether.
To summarize, the unexpected behavior concerns the toast components, which seem to be held till the end of the method execution to finally be displayed on the screen. The boolean attributes loading_data and building_plot correctly switch between True/False, though.
Specifics (please complete the following information):
- Python Version: 3.11.14
- Reflex Version: bug with both 0.8.26 and 0.8.27
- OS: Manjaro (Linux)
- Browser (Optional): Brave
Edit 1
Apparently, splitting the handle_on_load method into multiple events fixes the issue, although I would still expect the previous version to work correctly. Here's the on_load handler splitted:
@rx.event
async def handle_on_load_refactored(self):
self.loading_data = True
return State.load_data
@rx.event
async def load_data(self):
await asyncio.sleep(5)
self.loading_data = False
yield rx.toast.info("Data loaded!")
yield State.build_plot
@rx.event
async def build_plot(self):
self.building_plot = True
yield
await asyncio.sleep(5)
self.building_plot = False
yield rx.toast.info("Plot built!")