R

ReflexKR

Documentación de Reflex

Desarrollo web full stack con Python y Reflex

·

Resumen del curso

1

Conoce Reflex y prepara tu entorno

2

Dibujar la pantalla con componentes

3

State y Vars: que los datos dibujen la pantalla

4

Eventos y formularios: añadir clientes

5

Transformar datos y gráficos

6

Resumen, depuración y próximos pasos

·

Apéndice

Desarrollo web full stack con Python y Reflex

Apéndice

A. Código completo (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. Glosario

TérminoSignificado
Full stackDesarrollo que abarca tanto la interfaz (frontend) como el servidor (backend)
ComponenteUna pieza de la pantalla. En Reflex, una llamada a función rx.xxx(...)
propsValores de configuración que se pasan a un componente, como argumentos de palabra clave
StateClase que contiene los datos de la app y sus manejadores de eventos. Existe en el servidor, una por sesión
VarExpresión que apunta a una variable del State dentro del código de pantalla. Su valor se rellena en el navegador
computed varVariable declarada con @rx.var que se calcula a partir de otro estado
Manejador de eventosMétodo del State decorado con @rx.event. Se ejecuta en el servidor como respuesta a una acción del usuario
Componente controladoEnfoque en el que el State decide el valor o el estado de un elemento de la pantalla (open=, value=)
Tiempo de compilaciónEl momento, al arrancar la app, en que las funciones de pantalla se convierten en código React
Tiempo de ejecuciónEl momento en que la app está en marcha y el usuario interactúa con ella. Es cuando se ejecutan los manejadores de eventos
WebSocketForma de comunicación en la que navegador y servidor mantienen una conexión abierta e intercambian mensajes en ambos sentidos
Hot reloadFunción que, al guardar el código, vuelve a compilarlo y aplica los cambios automáticamente sin detener el servidor

C. Dividirlo en entradas de blog

Si conviertes cada lección en un artículo, tendrás una serie de 6 entregas.

EntregaTítulo de ejemploLección que cubre
1Crea apps web solo con Python: primeros pasos con Reflex (+ solución de errores en Windows)Lección 1
2Dibuja la pantalla sin HTML: componentes y estilos en ReflexLección 2
3Por qué len() no funciona en Reflex: State y VarsLección 3
4Añadir datos con formularios y diálogosLección 4
5Agregar datos con Python y dibujar gráficosLección 5
68 errores con los que se topa todo principiante en ReflexLección 6, 6-2
  • Convierte los bloques de cita de Nota para el instructor en explicaciones dentro del texto o en un recuadro de "Consejo".
  • Si al final de cada artículo incluyes el código completo hasta ese punto y una captura de la app en marcha, los lectores podrán incorporarse a mitad de la serie.
  • Haz las capturas del gráfico cuando haya terminado la animación (2 segundos o más).
  • Indica al principio del artículo "Basado en Reflex 0.10.0". La API de Reflex cambia rápido, y especificar la versión ahorra a los lectores muchas pruebas y errores.

D. Guía para grabar el curso en vídeo

  • Distribución de la pantalla: VS Code a la izquierda, el navegador a la derecha y la terminal abajo. Así se ve en una sola pantalla el momento en que guardas → hot reload → la pantalla cambia.
  • Tamaño de letra: fuente del editor de 18 pt o más y zoom del navegador del 125 % o más.
  • Escribe el código poco a poco: no pegues el código terminado; escríbelo siguiendo el orden de los bloques de código de cada lección y enseña la pantalla cada vez que guardes.
  • Muestra los errores a propósito: el error de 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.
  • Capítulos: si en la descripción del vídeo pones marcas de tiempo con el número de lección y sección (1-1, 1-2 …), se corresponderán directamente con este material.
  • Ajusta la duración: los minutos (min) de cada sección se refieren a una clase en directo. Un vídeo grabado y editado suele quedarse en aproximadamente la mitad.

← Anterior

Lección 6 · Resumen, depuración y próximos pasos

Recibe avisos de nuevas lecciones

Te avisaremos por correo cuando este curso tenga lecciones nuevas o se abra un curso de continuación.

Datos: tu correo electrónico · Finalidad: avisos de nuevas lecciones o de la publicación de este curso · Conservación: hasta que pidas que lo borremos. No lo usamos para nada más ni lo compartimos. Responde a cualquier aviso y lo borraremos enseguida.

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.

Se muestra como texto plano, sin enlaces ni formato.

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
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex