Skip to content

Commit 52af1dd

Browse files
Add documentation for decentralized event handlers
Co-Authored-By: khaleel@reflex.dev <khaleel.aladhami@gmail.com>
1 parent 0c909a7 commit 52af1dd

File tree

2 files changed

+152
-0
lines changed

2 files changed

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

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)