R

ReflexKR

Reflex-Dokumentation

Full-Stack-Webentwicklung mit Python und Reflex

·

Kursüberblick

1

Reflex kennenlernen und Umgebung einrichten

2

Die Oberfläche mit Komponenten zeichnen

3

State und Vars: Daten zeichnen die Oberfläche

4

Events und Formulare: Kunden hinzufügen

5

Daten aufbereiten und Diagramme

6

Zusammenfassung, Debugging und nächste Schritte

·

Anhang

Full-Stack-Webentwicklung mit Python und Reflex
Lektion 4

Zeit 2:10–2:55

Events und Formulare: Kunden hinzufügen

Am Ende dieser Lektion öffnet der Button „Add User“ einen Dialog. Sendest du das Formular ab, landet der Kunde in der Tabelle, und der Dialog schließt sich automatisch. Damit reagiert die Oberfläche zum ersten Mal auf das, was Nutzer tun, und genau das ist der wichtigste Schritt.

4-1. Event-Handler (10 Min.)

Ein Event-Handler ist eine Methode im State, die mit @rx.event dekoriert ist. Nur Event-Handler können den State ändern.

class State(rx.State):
    users: list[User] = [...]

    @rx.event
    def add_user(self, form_data: dict):
        self.users.append(User(**form_data))
  • Handler laufen als echtes Python auf dem Server. Hier ist self.users keine Var, sondern eine richtige Liste. Du kannst also nach Belieben append, len, if, for und sogar externe Bibliotheken verwenden.
  • Änderst du self.users, erkennt Reflex die Änderung, schickt sie an den Browser, und Tabelle und Badge werden automatisch neu gezeichnet. Code, der die Oberfläche direkt anpasst, gibt es nicht.
  • User(**form_data) entpackt das Dictionary und übergibt die Einträge als Keyword-Argumente: {"name": "Kim", "email": "...", "gender": "Male"} → User(name="Kim", email="...", gender="Male").

Hinweis für Lehrende — Stell das der Tabelle aus Lektion 3 gegenüber: „In der Oberflächen-Funktion ist es eine Var, also kein len. Im Handler ist es ein echter Wert, also geht len.“ Wer diesen Gegensatz verstanden hat, hat die halbe Miete in Reflex.

4-2. Das Formular bauen (10 Min.)

rx.form(
    rx.flex(
        rx.input(placeholder="User Name", name="name", required=True),
        rx.input(placeholder="user@reflex.dev", name="email"),
        rx.select(
            ["Male", "Female"],
            placeholder="Select gender",
            default_value="Male",
            name="gender",
            custom_attrs={"aria-label": "Gender"},
        ),
        rx.flex(
            rx.dialog.close(
                rx.button("Cancel", type="button", variant="soft", color_scheme="gray"),
            ),
            rx.button("Submit", type="submit"),
            spacing="3",
            justify="end",
        ),
        direction="column",
        spacing="4",
    ),
    on_submit=State.add_user,
    reset_on_submit=False,
)
  • name= ist der gemeinsame Schlüssel. Beim Absenden wird aus dem name jedes Eingabefelds ein Schlüssel im Dictionary form_data. Diese Namen müssen exakt den Feldnamen von User (name, email, gender) entsprechen, damit User(**form_data) funktioniert.
  • An on_submit=State.add_user übergibst du den Handler über die Klasse und ohne ihn aufzurufen. Das Dictionary aus dem Formular wird automatisch als form_data eingesetzt.
  • Mit required=True verhindert der Browser, dass das Formular mit leerem Feld abgeschickt wird.
  • Wichtig ist type="button" beim Cancel-Button. Buttons in einem Formular sind standardmäßig submit. Vergisst du das, wird auch beim Klick auf Abbrechen ein Kunde hinzugefügt.
  • rx.flex ist eine Box mit display="flex". Mit direction="column" werden die Kinder untereinander angeordnet, spacing legt den Abstand fest.
  • Mit custom_attrs hängst du HTML-Attribute an, die Reflex nicht kennt. Hier ist es ein Label für Screenreader.

4-3. In einen Dialog packen (10 Min.)

def add_customer_button() -> rx.Component:
    return rx.dialog.root(
        rx.dialog.trigger(                       # Element, das beim Klick den Dialog öffnet
            rx.button(
                rx.icon("plus", size=18),
                rx.text("Add User", size="2"),
            ),
        ),
        rx.dialog.content(                       # Inhalt des Dialogs
            rx.dialog.title("Add New User"),
            rx.dialog.description("Fill the form with the user's info"),
            rx.form(...),                         # das Formular aus 4-2
            max_width="450px",
        ),
    )
  • Für rx.icon("plus") verwendest du direkt die Namen der Lucide-Icons.
  • Die fertige Funktion fügst du als add_customer_button() auf der rechten Seite des Headers ein (nach der Titel-Box, im selben Elternelement).
  • Teile der Oberfläche in Funktionen auszulagern ist ganz normales Python. Eine besondere Syntax brauchst du dafür nicht.

Im Browser prüfen — Ganz rechts im Header erscheint ein blauer Button „+ Add User“.

localhost:3000

Ausprobieren

Customers

2

Your customer directory and audience breakdown.

NameEmailGender
Danilo Sousadanilo@example.comMale
Zahra Ambessazahra@example.comFemale
Schritt 4-3: Klick auf Add User und füge einen Kunden hinzu. Das klappt, aber der Dialog schließt sich nicht.

Klickst du auf den Button, wird der Hintergrund abgedunkelt und der Dialog erscheint; beim Geschlecht ist Male vorausgewählt. Gib in der Vorschau oben selbst Werte ein und klick auf Submit.

Wenn du den Stand bis hierhin ausführst, fällt dir ein Problem auf: Der Kunde wird zwar hinzugefügt, aber der Dialog schließt sich nicht. Ob der Dialog offen oder geschlossen ist, verwaltet der Browser ganz allein. Der Handler auf dem Server hat also keine Möglichkeit, ihn zu schließen.

4-4. Den Dialog über den State steuern (10 Min.)

Die Lösung: Wir verschieben die Information „Ist der Dialog offen?“ in den State. Dieses Muster heißt kontrollierte Komponente (Controlled Component).

class State(rx.State):
    users: list[User] = [...]
    add_user_dialog_open: bool = False          # 1) Offen-Zustand im State

    @rx.event
    def set_add_user_dialog_open(self, open_: bool):   # 2) Setter selbst definieren
        self.add_user_dialog_open = open_

    @rx.event
    def add_user(self, form_data: dict):
        self.users.append(User(**form_data))
        self.add_user_dialog_open = False      # 3) nach dem Absenden schließen
rx.dialog.root(
    ...,
    open=State.add_user_dialog_open,                  # der State bestimmt, ob der Dialog offen ist
    on_open_change=State.set_add_user_dialog_open,    # Öffnen/Schließen durch Nutzer wird in den State übernommen
)
  • Gibst du nur open= an und vergisst on_open_change, ändert sich beim Klick auf den Trigger-Button der State nicht, und der Dialog geht gar nicht erst auf. Die beiden gehören immer zusammen.
  • on_open_change übergibt dem Handler beim Öffnen True und beim Schließen (Cancel, ESC, Klick daneben) False.
  • Reflex 0.10 hat keine automatischen Setter. In älteren Materialien findest du oft Code, der State.set_variablenname ohne Definition verwendet. In 0.10 werden solche Methoden aber nicht mehr erzeugt, du musst sie also wie oben selbst definieren.
  • Der Parameter heißt open_, damit er nicht mit der eingebauten Python-Funktion open kollidiert. Das ist eine gängige Konvention.
  • Obwohl reset_on_submit=False gesetzt ist, sind die Eingabefelder beim nächsten Öffnen leer: Schließt sich der Dialog, wird sein Inhalt aus der Seite entfernt und beim erneuten Öffnen frisch gezeichnet.

4-5. Der Weg eines einzigen Klicks (5 Min.)

  1. Der Nutzer klickt auf Submit.
  2. Der Browser sammelt die Eingaben als {"name": ..., "email": ..., "gender": ...}.
  3. Diese Werte gehen per WebSocket an den Server.
  4. Der Server sucht den State dieses Nutzers und führt add_user(form_data) aus.
  5. Nur die geänderten Variablen (users, add_user_dialog_open) kommen zum Browser zurück.
  6. Tabelle und Badge werden neu gezeichnet, und der Dialog schließt sich.

Im Browser prüfen — Mit allen Änderungen bis 4-4 schließt sich der Dialog nach Submit, die Tabelle bekommt eine dritte Zeile, und das Badge springt auf 3. Bleibt der Dialog offen, prüfst du noch einmal open= und on_open_change= aus 4-4.

localhost:3000

Ausprobieren

Customers

2

Your customer directory and audience breakdown.

NameEmailGender
Danilo Sousadanilo@example.comMale
Zahra Ambessazahra@example.comFemale
Lektion 4 fertig: Nach dem Absenden schließt sich der Dialog, und die Zahl im Badge steigt.

Übungen

  1. Füge bei der Auswahl des Geschlechts die Option "Other" hinzu.
  2. Gib dem E-Mail-Feld type="email" und probiere aus, was beim Absenden einer ungültigen Adresse passiert.
  3. Ist der Name schon vorhanden, soll der Handler den Kunden nicht hinzufügen, sondern return rx.toast.error("Kunde existiert bereits") zurückgeben. Gib bei Erfolg zusätzlich rx.toast.success(...) zurück.

Checkpoint

  • Fügst du über Add User einen Kunden hinzu, ändern sich Tabelle und Badge.
  • Nach dem Absenden schließt sich der Dialog automatisch.
  • Ein Klick auf Cancel fügt keinen Kunden hinzu.
  • Du kannst den Zusammenhang zwischen name=, form_data und den Feldern von User erklären.

← Zurück

Lektion 3 · State und Vars: Daten zeichnen die Oberfläche

Weiter →

Lektion 5 · Daten aufbereiten und Diagramme

Über neue Lektionen informiert werden

Wir schicken dir eine E-Mail, wenn dieser Kurs neue Lektionen bekommt oder ein Folgekurs erscheint.

Erhoben: deine E-Mail-Adresse · Zweck: Hinweise auf neue Lektionen oder den Start dieses Kurses · Speicherdauer: bis du die Löschung verlangst. Keine andere Nutzung, keine Weitergabe. Antworte einfach auf eine Benachrichtigung, dann löschen wir sie sofort.

Fragen & Antworten

Frag alles zu dieser Lektion. Fragen aus allen Sprachversionen dieser Seite erscheinen hier gemeinsam.

Wird als reiner Text angezeigt, ohne Links oder Formatierung.

R

ReflexKR

Python und Reflex zum Anfassen. Alle Beispiele wurden mit Reflex 0.10.0 ausgeführt und geprüft.

ReflexKR ist kostenlos und ohne Werbebanner. Wenn es dir geholfen hat, kannst du es mit einem Kaffee unterstützen. ☕ Spendier uns einen Kaffee

Hinweis zu Affiliate-Links
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex