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,
)| Término | Significado |
|---|---|
| Full stack | Desarrollo que abarca tanto la interfaz (frontend) como el servidor (backend) |
| Componente | Una pieza de la pantalla. En Reflex, una llamada a función rx.xxx(...) |
| props | Valores de configuración que se pasan a un componente, como argumentos de palabra clave |
| State | Clase que contiene los datos de la app y sus manejadores de eventos. Existe en el servidor, una por sesión |
| Var | Expresión que apunta a una variable del State dentro del código de pantalla. Su valor se rellena en el navegador |
| computed var | Variable declarada con @rx.var que se calcula a partir de otro estado |
| Manejador de eventos | Método del State decorado con @rx.event. Se ejecuta en el servidor como respuesta a una acción del usuario |
| Componente controlado | Enfoque en el que el State decide el valor o el estado de un elemento de la pantalla (open=, value=) |
| Tiempo de compilación | El momento, al arrancar la app, en que las funciones de pantalla se convierten en código React |
| Tiempo de ejecución | El momento en que la app está en marcha y el usuario interactúa con ella. Es cuando se ejecutan los manejadores de eventos |
| WebSocket | Forma de comunicación en la que navegador y servidor mantienen una conexión abierta e intercambian mensajes en ambos sentidos |
| Hot reload | Función que, al guardar el código, vuelve a compilarlo y aplica los cambios automáticamente sin detener el servidor |
Si conviertes cada lección en un artículo, tendrás una serie de 6 entregas.
| Entrega | Título de ejemplo | Lección que cubre |
|---|---|---|
| 1 | Crea apps web solo con Python: primeros pasos con Reflex (+ solución de errores en Windows) | Lección 1 |
| 2 | Dibuja la pantalla sin HTML: componentes y estilos en Reflex | Lección 2 |
| 3 | Por qué len() no funciona en Reflex: State y Vars | Lección 3 |
| 4 | Añadir datos con formularios y diálogos | Lección 4 |
| 5 | Agregar datos con Python y dibujar gráficos | Lección 5 |
| 6 | 8 errores con los que se topa todo principiante en Reflex | Lección 6, 6-2 |
Nota para el instructor en explicaciones dentro del texto o en un recuadro de "Consejo".len() de la lección 3, el type olvidado en el botón Cancel de la lección 4 y el diálogo que no se cierra merecen mucho la pena reproducirse adrede.Recibe avisos de nuevas lecciones
Te avisaremos por correo cuando este curso tenga lecciones nuevas o se abra un curso de continuación.
R
ReflexKR
Aprende Python y Reflex haciendo. Todos los ejemplos se ejecutaron y verificaron en Reflex 0.10.0.
ReflexKR es gratis y sin banners publicitarios. Si te ayudó, puedes apoyarlo con un café. ☕ Invítanos un café
Aviso de afiliados© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Preguntas y respuestas
Pregunta lo que quieras sobre esta lección. Aquí se reúnen las preguntas de todas las versiones de idioma de esta página.