설명보다 먼저 눌러 봅시다. 아래 버튼을 누르면 숫자가 1씩 올라갑니다. 이 교시가 끝나면 이 열 줄 남짓한 코드가 어떻게 동작하는지 설명할 수 있습니다.
import reflex as rx
class CounterState(rx.State):
count: int = 0
@rx.event
def increment(self):
self.count += 1
def counter_increment():
return rx.hstack(
rx.heading(CounterState.count, as_="h2"),
rx.button("Increment", on_click=CounterState.increment),
)localhost:3000
직접 눌러 보세요코드는 세 부분으로 나뉩니다.
| 부분 | 코드 | 하는 일 |
|---|---|---|
| State | class CounterState(rx.State) | 바뀌는 데이터(count)를 담는 상자 |
| 이벤트 핸들러 | def increment(self) | 데이터를 바꾸는 함수 |
| 이벤트 트리거 | on_click=CounterState.increment | "누르면 이 함수를 불러라"라는 연결 |
버튼을 누르면 increment가 서버에서 실행되고, count가 바뀌면 Reflex가 그 값을 쓰는 화면만 알아서 다시 그립니다. 화면을 직접 고치는 코드는 한 줄도 없습니다.
앱에는 시간이 지나며 바뀌는 데이터가 있습니다. 카운터의 숫자, 로그인 여부, 장바구니 목록 같은 것들입니다. Reflex에서는 이런 데이터를 State 클래스에 담습니다.
rx.State를 상속한 클래스를 만들고, 그 안에 변수를 적습니다. 이 변수를 Var(state var)라고 부릅니다.count: int), 기본값을 줄 수 있습니다(= 0).화면에서 Var를 쓰려면 MyState.count처럼 클래스 이름으로 가리킵니다. 자식으로 넣어도 되고, props 값으로 줘도 됩니다.
class MyState(rx.State):
count: int = 0
color: str = "red"
def counter():
return rx.hstack(
# The heading `color` prop is set to the `color` var in MyState.
rx.heading("Count: ", as_="h2", color=MyState.color),
# The `count` var in `MyState` is passed as a child to the heading component.
rx.heading(MyState.count, as_="h2"),
)localhost:3000
실행 화면같은 Var를 여러 컴포넌트에서 써도 됩니다. 값이 바뀌면 그 Var를 쓰는 곳이 모두 함께 바뀝니다.
알아두기 — State를 바꿀 수 있는 것은 이벤트 핸들러뿐입니다. 화면 코드에서 MyState.count = 5처럼 직접 값을 넣을 수는 없습니다.
State 안에 정의한 메서드 중 데이터를 바꾸는 것을 이벤트 핸들러라고 합니다. on_click처럼 컴포넌트에 있는 특별한 props를 이벤트 트리거라고 하며, 트리거와 핸들러를 연결하면 화면이 사용자의 행동에 반응합니다.
핸들러 위의 @rx.event는 꼭 붙이는 것을 권장합니다. 이 데코레이터가 있으면 에디터와 타입 검사기가 "이 핸들러에 인자를 몇 개, 어떤 타입으로 넘겨야 하는지"를 확인해 줘서 실수를 미리 잡을 수 있습니다.
핸들러도 일반 함수처럼 인자를 받을 수 있습니다. 1씩, 5씩 올리는 버튼을 하나의 핸들러로 만들어 봅니다.
class CounterState2(rx.State):
count: int = 0
@rx.event
def increment(self, amount: int):
self.count += amount
def counter_variable():
return rx.hstack(
rx.heading(CounterState2.count, as_="h2"),
rx.button("Increment by 1", on_click=lambda: CounterState2.increment(1)),
rx.button("Increment by 5", on_click=lambda: CounterState2.increment(5)),
)localhost:3000
직접 눌러 보세요lambda: CounterState2.increment(1)처럼 lambda로 감싸서 "누르면 1을 넘겨 부른다"는 뜻을 드러냅니다.on_click=CounterState2.increment(1)처럼 바로 써도 똑같이 동작합니다. 이 코드는 핸들러를 지금 실행하지 않고, "누르면 amount=1로 실행하라"는 이벤트 정보만 만들어 둡니다. 핸들러 코드는 버튼을 누를 때 서버에서 실행됩니다.on_click은 핸들러에 아무 값도 넘기지 않지만, 값을 넘겨 주는 트리거도 있습니다. on_blur는 입력창에서 포커스가 빠져나갈 때(다른 곳을 클릭하거나 Tab을 누를 때) 입력된 글자를 핸들러에 넘겨 줍니다.
class TextState(rx.State):
text: str = ""
@rx.event
def update_text(self, new_text: str):
self.text = new_text
def text_input():
return rx.vstack(
rx.heading(TextState.text, as_="h2"),
rx.input(default_value=TextState.text, on_blur=TextState.update_text),
)localhost:3000
직접 눌러 보세요알아두기 — 핸들러의 인자 개수는 트리거가 넘겨 주는 값의 개수와 같아야 합니다. on_blur는 값 하나를 넘기므로 update_text도 new_text 하나를 받습니다. 개수가 다르면 에러가 납니다.
CounterState에 decrement 핸들러를 추가하고, 숫자를 1씩 줄이는 버튼을 만들어 보세요.counter_variable에 "Reset" 버튼을 추가해 count를 0으로 되돌려 보세요. 인자를 받는 핸들러로 만들 수 있을까요?on_blur 대신 on_change를 써 보세요. 글자를 칠 때마다 제목이 바뀝니다.클래스이름.변수이름으로 가리킬 수 있다.on_click에 인자를 넣어 핸들러를 연결해도 핸들러가 바로 실행되지 않는 이유를 안다.새 교시·새 강의 소식 받기
이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.
R
ReflexKR
눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.
ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.
© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
질문과 답변
이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.