Skip to content

Commit a59b831

Browse files
Add documentation for decentralized event handlers (#1347)
* Add documentation for decentralized event handlers Co-Authored-By: [email protected] <[email protected]> * Address PR feedback: Remove incorrect claims about reusing event handlers Co-Authored-By: [email protected] <[email protected]> * Address PR feedback: Use @rx.event consistently and rename ModernState to DecentralizedState Co-Authored-By: [email protected] <[email protected]> * Address PR feedback: Update @event to @rx.event in documentation text Co-Authored-By: [email protected] <[email protected]> * Address PR feedback: Update Key differences section to use @rx.event consistently Co-Authored-By: [email protected] <[email protected]> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: [email protected] <[email protected]>
1 parent 0c909a7 commit a59b831

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
```python exec
2+
import reflex as rx
3+
```
4+
5+
# Decentralized Event Handlers
6+
7+
## Overview
8+
9+
Decentralized event handlers allow you to define event handlers outside of state classes, providing more flexible code organization. This feature was introduced in Reflex v0.7.10 and enables a more modular approach to event handling.
10+
11+
With decentralized event handlers, you can:
12+
- Organize event handlers by feature rather than by state class
13+
- Separate UI logic from state management
14+
- Create more maintainable and scalable applications
15+
16+
## Basic Usage
17+
18+
To create a decentralized event handler, use the `@rx.event` decorator on a function that takes a state instance as its first parameter:
19+
20+
```python demo exec
21+
import reflex as rx
22+
23+
class MyState(rx.State):
24+
count: int = 0
25+
26+
@rx.event
27+
def increment(state: MyState, amount: int = 1):
28+
state.count += amount
29+
30+
def decentralized_event_example():
31+
return rx.vstack(
32+
rx.heading(f"Count: {MyState.count}"),
33+
rx.hstack(
34+
rx.button("Increment by 1", on_click=increment()),
35+
rx.button("Increment by 5", on_click=increment(5)),
36+
rx.button("Increment by 10", on_click=increment(10)),
37+
),
38+
spacing="4",
39+
align="center",
40+
)
41+
```
42+
43+
In this example:
44+
1. We define a `MyState` class with a `count` variable
45+
2. We create a decentralized event handler `increment` that takes a `MyState` instance as its first parameter
46+
3. We use the event handler in buttons, passing different amounts to increment by
47+
48+
## Compared to Traditional Event Handlers
49+
50+
Here's a comparison between traditional event handlers defined within state classes and decentralized event handlers:
51+
52+
```python box
53+
# Traditional event handler within a state class
54+
class TraditionalState(rx.State):
55+
count: int = 0
56+
57+
@rx.event
58+
def increment(self, amount: int = 1):
59+
self.count += amount
60+
61+
# Usage in components
62+
rx.button("Increment", on_click=TraditionalState.increment(5))
63+
64+
# Decentralized event handler outside the state class
65+
class DecentralizedState(rx.State):
66+
count: int = 0
67+
68+
@rx.event
69+
def increment(state: DecentralizedState, amount: int = 1):
70+
state.count += amount
71+
72+
# Usage in components
73+
rx.button("Increment", on_click=increment(5))
74+
```
75+
76+
Key differences:
77+
- Traditional event handlers use `self` to reference the state instance
78+
- Decentralized event handlers explicitly take a state instance as the first parameter
79+
- Both approaches use the same syntax for triggering events in components
80+
- Both can be decorated with `@rx.event` respectively
81+
82+
## Best Practices
83+
84+
### When to Use Decentralized Event Handlers
85+
86+
Decentralized event handlers are particularly useful in these scenarios:
87+
88+
1. **Large applications** with many event handlers that benefit from better organization
89+
2. **Feature-based organization** where you want to group related event handlers together
90+
3. **Separation of concerns** when you want to keep state definitions clean and focused
91+
92+
### Type Annotations
93+
94+
Always use proper type annotations for your state parameter and any additional parameters:
95+
96+
```python box
97+
@rx.event
98+
def update_user(state: UserState, name: str, age: int):
99+
state.name = name
100+
state.age = age
101+
```
102+
103+
### Naming Conventions
104+
105+
Follow these naming conventions for clarity:
106+
107+
1. Use descriptive names that indicate the action being performed
108+
2. Use the state class name as the type annotation for the first parameter
109+
3. Name the state parameter consistently across your codebase (e.g., always use `state` or the first letter of the state class)
110+
111+
### Organization
112+
113+
Consider these approaches for organizing decentralized event handlers:
114+
115+
1. Group related event handlers in the same file
116+
2. Place event handlers near the state classes they modify
117+
3. For larger applications, create a dedicated `events` directory with files organized by feature
118+
119+
```python box
120+
# Example organization in a larger application
121+
# events/user_events.py
122+
@rx.event
123+
def update_user(state: UserState, name: str, age: int):
124+
state.name = name
125+
state.age = age
126+
127+
@rx.event
128+
def delete_user(state: UserState):
129+
state.name = ""
130+
state.age = 0
131+
```
132+
133+
### Combining with Other Event Features
134+
135+
Decentralized event handlers work seamlessly with other Reflex event features:
136+
137+
```python box
138+
# Background event
139+
@rx.event(background=True)
140+
async def long_running_task(state: AppState):
141+
# Long-running task implementation
142+
pass
143+
144+
# Event chaining
145+
@rx.event
146+
def process_form(state: FormState, data: dict):
147+
# Process form data
148+
return validate_data # Chain to another event
149+
```

pcweb/components/docpage/sidebar/sidebar_items/learn.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ def get_sidebar_items_backend():
147147
events.page_load_events,
148148
events.background_events,
149149
events.event_actions,
150+
events.decentralized_event_handlers,
150151
],
151152
),
152153
create_item(

0 commit comments

Comments
 (0)