이번 교시에는 고객 데이터를 State에 두고, 테이블과 배지가 그 데이터를 보고 그려지게 만듭니다. Reflex에서 가장 중요한 개념인 Var를 배우는 시간입니다.
import dataclasses
@dataclasses.dataclass
class User:
name: str
email: str
gender: strUser(name="...", email="...", gender="...")로 만듭니다.{"name": ...})를 써도 되지만, dataclass를 쓰면 필드 이름을 타이핑할 때 오타를 편집기가 잡아주고, 화면 코드에서 user.name처럼 점으로 접근할 수 있습니다.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"),
]rx.State를 상속한 클래스의 클래스 변수가 상태 변수(state var)가 됩니다. 여기 적은 값은 초깃값입니다.: list[User])은 필수입니다. Reflex가 타입을 보고 브라우저로 보낼 형식(JSON)과 쓸 수 있는 메서드를 정합니다.1교시에서 "화면 함수는 앱 시작 때 한 번만 실행된다"고 했습니다. 그러면 화면 함수 안에서 State.users를 쓰면 무엇이 나올까요? 실제로 출력해 보면 이렇습니다.
>>> type(State.users).__name__
'ArrayCastedVar'
>>> print(State.users.length())
reflex___state____state__tutorial_261019___tutorial_261019____state.users_rx_state_.length고객 리스트가 아니라 JavaScript 표현식이 나옵니다. 이것이 Var입니다. 화면 함수가 실행되는 시점에는 아직 사용자도, 데이터도 없기 때문에 "나중에 브라우저에서 이 값을 읽어라"는 약속만 만들어 두는 것입니다.
그래서 파이썬 문법 중 일부는 Var에 쓸 수 없습니다. Reflex 0.10에서 실제로 나오는 에러와 대안입니다.
| 하고 싶은 것 | 안 되는 코드 | 나오는 에러 | Reflex 방식 |
|---|---|---|---|
| 개수 세기 | len(State.users) | TypeError: object of type 'ArrayCastedVar' has no len() | State.users.length() |
| 조건 분기 | "a" if State.n > 1 else "b" | VarTypeError: Cannot convert Var ... to bool | rx.cond(State.n > 1, "a", "b") |
| 반복 | for u in State.users: | VarTypeError: Cannot iterate over Var ... | rx.foreach(State.users, show_user) |
| 복잡한 가공 | 화면 함수 안에서 계산 | — | 이벤트나 @rx.var(computed var)에서 계산 |
반대로 Var끼리 비교·산술(State.page + 1), f-string 안에 Var 넣기(f"전체 {State.total}명")는 잘 됩니다. 연산 자체가 JavaScript 표현식으로 번역되기 때문입니다.
강사 노트 — 이 표가 이 강의에서 가장 중요합니다. 입문자가 Reflex에서 만나는 에러의 대부분이 여기서 나옵니다. 영상에서는 len(State.users)를 일부러 써서 에러 화면을 보여주고, "왜 안 될까?"를 질문한 뒤 위 print 결과로 답하는 흐름을 추천합니다.
이제 헤더의 임시 배지를 실제 고객 수로 바꿉니다.
rx.badge(
State.users.length(), # "2" 대신 Var
variant="soft",
color_scheme="gray",
radius="full",
),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",
)User로 적었지만, 실제로 들어오는 것은 User를 가리키는 Var입니다. user.name도 "이 줄 고객의 name을 읽어라"는 표현식이 됩니다. dataclass로 필드를 선언해 둔 덕분에 점 접근이 가능합니다.style={"_hover": {...}}는 마우스를 올렸을 때의 스타일입니다. _hover, _focus처럼 _로 시작하는 키는 CSS의 :hover 같은 상태 선택자입니다.헤더 아래, 카드 안에 두 번째 자식으로 테이블을 넣습니다.
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",
),root > header(제목 행) + body(데이터 행들) > row > cell. HTML의 <table>, <thead>, <tbody>, <tr>, <td>에 대응합니다.rx.foreach(리스트 Var, 함수)는 브라우저에서 리스트의 각 항목에 함수를 적용합니다. 함수를 호출하지 않고 이름만 넘깁니다(show_user()가 아니라 show_user).for를 써도 됩니다. 컴파일 타임에 값이 정해져 있기 때문입니다. 예: *[rx.table.column_header_cell(h) for h in ["Name", "Email", "Gender"]]브라우저 확인 — 카드 안에 고객 2명의 테이블이 생기고, 배지의 2는 이제 State.users.length()에서 옵니다. 행에 마우스를 올리면 배경이 연한 회색으로 바뀝니다.
localhost:3000
실행 화면Your customer directory and audience breakdown.
rx.cond를 써서 고객이 0명이면 테이블 대신 "아직 고객이 없습니다"를 보여주세요. 힌트: rx.cond(State.users.length() > 0, 테이블, rx.text(...))len(State.users)를 써서 에러 메시지를 직접 읽어 보세요.len/if/for를 쓸 수 없는지 설명할 수 있다.rx.foreach에 함수를 호출하지 않고 넘겨야 하는 이유를 안다.새 교시·새 강의 소식 받기
이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.
R
ReflexKR
눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.
ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.
© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
질문과 답변
이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.