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

Anhang

A. Der vollständige Code (tutorial_261019/tutorial_261019.py)

import dataclasses
from collections import Counter

import reflex as rx


@dataclasses.dataclass
class User:
    name: str
    email: str
    gender: str


class State(rx.State):
    users: list[User] = [
        User(name="Danilo Sousa", email="danilo@example.com", gender="Male"),
        User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"),
    ]
    users_for_graph: list[dict] = []
    add_user_dialog_open: bool = False

    @rx.event
    def set_add_user_dialog_open(self, open_: bool):
        self.add_user_dialog_open = open_

    @rx.event
    def add_user(self, form_data: dict):
        self.users.append(User(**form_data))
        self.transform_data()
        self.add_user_dialog_open = False

    @rx.event
    def transform_data(self):
        gender_counts = Counter(user.gender for user in self.users)

        self.users_for_graph = [
            {"name": gender_group, "value": count} for gender_group, count in gender_counts.items()
        ]


def show_user(user: User):
    return rx.table.row(
        rx.table.cell(user.name),
        rx.table.cell(user.email),
        rx.table.cell(user.gender),
        style={"_hover": {"bg": rx.color("gray", 3)}},
        align="center",
    )


def add_customer_button() -> rx.Component:
    return rx.dialog.root(
        rx.dialog.trigger(
            rx.button(
                rx.icon("plus", size=18),
                rx.text("Add User", size="2"),
            ),
        ),
        rx.dialog.content(
            rx.dialog.title(
                "Add New User",
            ),
            rx.dialog.description(
                "Fill the form with the user's info",
            ),
            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,
            ),
            max_width="450px",
        ),
        open=State.add_user_dialog_open,
        on_open_change=State.set_add_user_dialog_open,
    )


def graph():
    return rx.recharts.bar_chart(
        rx.recharts.cartesian_grid(
            horizontal=False, stroke_dasharray="3 3", stroke=rx.color("slate", 4)
        ),
        rx.recharts.x_axis(
            type_="number",
            allow_decimals=False,
            axis_line=False,
            tick_line=False,
            domain=[0, "dataMax + 1"],
        ),
        rx.recharts.y_axis(
            type_="category",
            data_key="name",
            axis_line=False,
            tick_line=False,
            width=64,
        ),
        rx.recharts.bar(
            data_key="value",
            fill=rx.color("accent", 9),
            radius=[0, 6, 6, 0],
            bar_size=28,
        ),
        data=State.users_for_graph,
        layout="vertical",
        width="100%",
        height=160,
        margin={"top": 0, "right": 16, "bottom": 0, "left": 0},
    )


def index() -> rx.Component:
    return rx.box(
        rx.box(
            rx.box(
                rx.box(
                    rx.heading("Customers", size="6", as_="h3", margin="0"),
                    rx.badge(
                        State.users.length(),
                        variant="soft",
                        color_scheme="gray",
                        radius="full",
                    ),
                    display="flex",
                    align_items="center",
                    gap="12px",
                ),
                rx.text(
                    "Your customer directory and audience breakdown.",
                    size="2",
                    color=rx.color("slate", 11),
                    margin_top="6px",
                ),
            ),
            add_customer_button(),
            display="flex",
            align_items="center",
            justify_content="space-between",
            flex_wrap="wrap",
            gap="16px",
            padding="24px",
        ),
        rx.box(
            rx.table.root(
                rx.table.header(
                    rx.table.row(
                        rx.table.column_header_cell("Name"),
                        rx.table.column_header_cell("Email"),
                        rx.table.column_header_cell("Gender"),
                    )
                ),
                rx.table.body(rx.foreach(State.users, show_user)),
                variant="ghost",
                size="3",
                width="100%",
            ),
            overflow_x="auto",
            width="100%",
            border_top=f"1px solid {rx.color('slate', 4)}",
            border_bottom=f"1px solid {rx.color('slate', 4)}",
            padding_x="12px",
        ),
        rx.box(
            rx.text("Audience breakdown", size="3", weight="bold"),
            rx.text(
                "Customers by gender",
                size="2",
                color=rx.color("slate", 11),
                margin_top="4px",
                margin_bottom="20px",
            ),
            graph(),
            padding="24px",
        ),
        width="100%",
        min_width="0",
        max_width="64em",
        margin_x="auto",
        margin_y="24px",
        border=f"1px solid {rx.color('slate', 5)}",
        border_radius="16px",
        background=rx.color("slate", 1),
        overflow="hidden",
        box_shadow="0 4px 24px rgba(0, 0, 0, 0.03)",
        style={
            "& *": {"box_sizing": "border-box"},
            "& p, & h3": {"text_align": "left"},
        },
    )


app = rx.App()
app.add_page(
    index,
    title="Customer Data App",
    description="A simple app to manage customer data.",
    on_load=State.transform_data,
)

B. Glossar

BegriffBedeutung
Full StackEntwicklung, die sowohl die Oberfläche (Frontend) als auch den Server (Backend) umfasst
KomponenteEin Baustein der Oberfläche. In Reflex ein einzelner Funktionsaufruf rx.xxx(...)
PropsEinstellungen, die einer Komponente mitgegeben werden. Werden als Keyword-Argumente übergeben
StateKlasse mit den Daten und Event-Handlern der App. Existiert auf dem Server pro Session
VarEin Ausdruck im Oberflächen-Code, der auf eine State-Variable verweist. Der Wert wird im Browser eingesetzt
Computed VarEine mit @rx.var deklarierte Variable, die aus anderem State berechnet wird
Event-HandlerEine State-Methode mit @rx.event. Läuft als Reaktion auf Nutzeraktionen auf dem Server
Kontrollierte KomponenteEin Muster, bei dem der State den Wert bzw. Zustand eines Elements bestimmt (open=, value=)
Compile-ZeitDer Moment beim Start der App, in dem Oberflächen-Funktionen in React-Code übersetzt werden
LaufzeitDie Phase, in der die App läuft und Nutzer mit ihr interagieren. Hier werden Event-Handler ausgeführt
WebSocketEin Kommunikationsverfahren, bei dem Browser und Server eine Verbindung offen halten und in beide Richtungen Nachrichten austauschen
Hot ReloadBeim Speichern wird der Code automatisch neu kompiliert und übernommen, ohne den Server neu zu starten

C. Als Blogserie aufteilen

Wenn du jede Lektion in einen eigenen Artikel überträgst, entsteht eine Serie aus 6 Teilen.

TeilBeispieltitelLektion
1Web-Apps nur mit Python: Einstieg in Reflex (+ Windows-Fehler beheben)Lektion 1
2Oberflächen ohne HTML: Komponenten und Styles in ReflexLektion 2
3Warum len() in Reflex nicht funktioniert: State und VarsLektion 3
4Daten über Formulare und Dialoge hinzufügenLektion 4
5Mit Python aggregieren und Diagramme zeichnenLektion 5
68 Fehler, auf die jeder Reflex-Einsteiger stößtLektion 6, Abschnitt 6-2
  • Die Zitatblöcke Hinweis für Lehrende schreibst du als Fließtext aus oder machst daraus einen „Tipp“-Kasten.
  • Wenn du am Ende jedes Artikels den vollständigen Code bis zu diesem Punkt und einen Screenshot der laufenden App einfügst, können Leser auch mittendrin einsteigen.
  • Screenshots von Diagrammen machst du erst, wenn die Animation fertig ist (nach mindestens 2 Sekunden).
  • Schreib oben in den Artikel „Stand: Reflex 0.10.0“. Die API von Reflex ändert sich schnell, und eine Versionsangabe erspart deinen Lesern viel Ausprobieren.

D. Leitfaden für Videokurse

  • Bildschirmaufteilung: links VS Code, rechts der Browser, unten das Terminal. So sieht man auf einem Bildschirm den Moment, in dem sich die Oberfläche nach dem Speichern per Hot Reload ändert.
  • Schriftgröße: Editor-Schrift mindestens 18 pt, Browser-Zoom mindestens 125 %.
  • Code Stück für Stück tippen: Füge nicht den fertigen Code ein, sondern tippe die Codeblöcke jeder Lektion der Reihe nach und zeig nach jedem Speichern die Oberfläche.
  • Fehler absichtlich zeigen: Der len()-Fehler aus Lektion 3, das fehlende type am Cancel-Button und der Dialog, der sich nicht schließt, aus Lektion 4 lohnen sich besonders, um sie bewusst nachzustellen.
  • Kapitelmarken: Setzt du in der Videobeschreibung Zeitstempel mit den Abschnittsnummern (1-1, 1-2 …), passen sie direkt zu diesem Material.
  • Länge abschätzen: Die Minutenangaben (Min.) der Abschnitte beziehen sich auf einen Live-Kurs. Ein geschnittenes Video ist meist etwa halb so lang.

← Zurück

Lektion 6 · Zusammenfassung, Debugging und nächste Schritte

Ü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