R

ReflexKR

Reflex公式ドキュメント

Reflexで始めるPythonフルスタックWeb開発

·

講座の概要

1

Reflexの紹介と開発環境

2

コンポーネントで画面を描く

3

StateとVar:データに画面を描かせる

4

イベントとフォーム:顧客を追加する

5

データ加工とチャート

6

まとめ、デバッグ、次のステップ

·

付録

Reflexで始めるPythonフルスタックWeb開発

付録

A. 完成コード全体 (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. 用語集

用語意味
フルスタック画面(フロントエンド)とサーバー(バックエンド)の両方を扱う開発
コンポーネント画面を構成する部品。Reflexではrx.xxx(...)という関数呼び出し1つ
propsコンポーネントに渡す設定値。キーワード引数で渡す
Stateアプリのデータとイベントハンドラをまとめたクラス。サーバー上にセッションごとに存在する
Var画面のコードの中でStateの変数を指す式。値はブラウザで埋められる
computed var@rx.varで宣言する、ほかの状態から計算される変数
イベントハンドラ@rx.eventを付けたStateのメソッド。ユーザーの操作に反応してサーバーで実行される
制御コンポーネント画面要素の値や状態をStateが決める方式(open=、value=)
コンパイル時アプリの起動時に、画面の関数がReactのコードに変換されるタイミング
実行時アプリが動いていて、ユーザーが操作しているタイミング。イベントハンドラが実行される
WebSocketブラウザとサーバーが接続を開いたままにして、双方向にメッセージをやり取りする通信方式
ホットリロードコードを保存すると、サーバーを止めずに自動で再コンパイルして反映する機能

C. ブログ記事に分けるには

1時限を1本の記事にすると、全6回のシリーズになります。

回タイトル例扱う時限
1Pythonだけでウェブアプリを作る、Reflex入門(+Windowsのエラー対処)1限目
2HTMLなしで画面を描く:Reflexのコンポーネントとスタイル2限目
3Reflexでlen()が使えない理由:StateとVar3限目
4フォームとダイアログでデータを追加する4限目
5Pythonで集計してチャートを描く5限目
6Reflex初心者が必ず出会うエラー8選6限目 6-2
  • 講師メモの引用ブロックは、本文の説明として書き直すか、「ヒント」ボックスに置き換えます。
  • 各記事の最後に、その時点までのコード全体と実行画面のスクリーンショットを載せておくと、読者が途中からでも追いつけます。
  • チャートのスクリーンショットは、アニメーションが終わってから(2秒以上待って)撮ります。
  • 記事の冒頭に「Reflex 0.10.0対応」と明記します。ReflexはAPIの変化が速いため、バージョンを書いておくだけで読者の試行錯誤を大きく減らせます。

D. 動画講座の制作ガイド

  • 画面レイアウト:左にVS Code、右にブラウザ、下にターミナルを配置します。保存 → ホットリロードで画面が変わる瞬間が、1つの画面に収まるようにします。
  • 文字サイズ:エディタのフォントは18pt以上、ブラウザの拡大率は125%以上にします。
  • コードは少しずつ入力する:完成したコードを貼り付けず、各時限のコードブロックの順に入力し、保存するたびに画面を見せます。
  • エラーはあえて見せる:3限目のlen()のエラー、4限目のCancelボタンのtypeの書き忘れ、閉じないダイアログは、わざと再現して見せる価値が大きいポイントです。
  • チャプターを付ける:動画の説明欄に時限・節の番号(1-1、1-2 …)でタイムスタンプを付けると、この教材とそのまま対応します。
  • 尺の調整:各節の(分)表記はライブ講義を基準にしています。編集した録画動画は、通常その半分程度の長さになります。

← 前へ

6限目 · まとめ、デバッグ、次のステップ

新しい授業・講座のお知らせを受け取る

この講座に授業が追加されたり、続きの講座が公開されたりしたらメールでお知らせします。

収集項目:メールアドレス・目的:この講座の新しい授業・公開のお知らせ・保有期間:解除のご依頼まで。他の目的には使わず、第三者にも提供しません。お知らせメールに返信いただければすぐに削除します。

質問と回答

この回について気になることを書き込んでください。すべての言語のページの質問がここに集まります。

リンクや書式なしで、そのままの文字で表示されます。

R

ReflexKR

触って学ぶPythonとReflex。すべての例はReflex 0.10.0で実際に動かして確認しています。

ReflexKRはバナー広告なし・無料で運営しています。役に立ったら、コーヒー一杯で応援してください。 ☕ コーヒーで応援する

アフィリエイトと支援について
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex