# Interaction Patterns Reference ## Reactive State Use bindable dataclasses for local page state. ```python from dataclasses import field from nicegui import binding, ui @binding.bindable_dataclass class PageState: selected_id: int | None = None items: list = field(default_factory=list) state = PageState() ui.label().bind_text_from(state, "selected_id") ``` ## File Upload Pattern - Validate extension and size before storing. - Delegate storage to a service method. - Notify success and failure explicitly. ```python async def handle_upload(e: ui.events.UploadEventArguments): try: if e.size > 10 * 1024 * 1024: raise ValueError("File too large") if not e.name.endswith(".pdf"): raise ValueError("Only PDF allowed") await file_service.store(e.content.read(), e.name) ui.notify(f"Uploaded: {e.name}", type="positive") except ValueError as err: ui.notify(str(err), type="negative") ui.upload(on_upload=handle_upload, auto_upload=True) ``` ## Form Submission Pattern - Bind UI inputs to dataclass fields. - Perform validation in the service layer. - Clear form state on success. ```python @binding.bindable_dataclass class FormData: name: str = "" email: str = "" data = FormData() ui.input("Name").bind_value(data, "name") ui.input("Email").bind_value(data, "email") async def on_submit(): try: await user_service.create_user(name=data.name, email=data.email) ui.notify("User created", type="positive") data.name = data.email = "" except ValueError as err: ui.notify(str(err), type="negative") ui.button("Submit").on_click(on_submit) ``` ## Real-Time Updates Decision Use SSE for one-way status streaming. Use WebSocket for bidirectional messaging. SSE endpoint example: ```python @app.get("/events/status") async def status_stream(): async def gen(): while True: yield f"data: {await get_status()}\\n\\n" await asyncio.sleep(1) return StreamingResponse(gen(), media_type="text/event-stream") ``` ## Background Work Pattern - Start long jobs in FastAPI background tasks. - Expose status via endpoint or streaming channel. - Guard buttons against duplicate submissions during in-flight tasks. ## Explicit Refresh Pattern Use @ui.refreshable and call refresh intentionally instead of polling unrelated state. ```python @ui.refreshable async def item_list(): items = await service.list() for item in items: ui.label(item.name) ui.button("Refresh").on_click(lambda: item_list.refresh()) ``` ## Links - NiceGUI action events: https://nicegui.io/documentation/section_action_events - FastAPI SSE: https://fastapi.tiangolo.com/advanced/server-sent-events/ - FastAPI WebSockets: https://fastapi.tiangolo.com/advanced/websockets/