Skip to content

Commit 76ac445

Browse files
Add documentation for rx.memo decorator (#1331)
* Add documentation for rx.memo decorator Co-Authored-By: Alek Petuskey <[email protected]> * Update rx.memo documentation with minor clarification Co-Authored-By: Alek Petuskey <[email protected]> * Update rx.memo documentation with type annotations and keyword argument requirements Co-Authored-By: Alek Petuskey <[email protected]> * Add @rx.event decorators to all event methods and fix greeting component Co-Authored-By: Alek Petuskey <[email protected]> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Alek Petuskey <[email protected]> Co-authored-by: Alek Petuskey <[email protected]>
1 parent b125bc2 commit 76ac445

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed

docs/library/other/memo.md

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
```python exec
2+
import reflex as rx
3+
from pcweb.pages.docs import styling
4+
```
5+
6+
# Memo
7+
8+
The `memo` decorator is used to optimize component rendering by memoizing components that don't need to be re-rendered. This is particularly useful for expensive components that depend on specific props and don't need to be re-rendered when other state changes in your application.
9+
10+
## Requirements
11+
12+
When using `rx.memo`, you must follow these requirements:
13+
14+
1. **Type all arguments**: All arguments to a memoized component must have type annotations.
15+
2. **Use keyword arguments**: When calling a memoized component, you must use keyword arguments (not positional arguments).
16+
17+
## Basic Usage
18+
19+
When you wrap a component function with `@rx.memo`, the component will only re-render when its props change. This helps improve performance by preventing unnecessary re-renders.
20+
21+
```python
22+
# Define a state class to track count
23+
class DemoState(rx.State):
24+
count: int = 0
25+
26+
@rx.event
27+
def increment(self):
28+
self.count += 1
29+
30+
# Define a memoized component
31+
@rx.memo
32+
def expensive_component(label: str) -> rx.Component:
33+
return rx.vstack(
34+
rx.heading(label),
35+
rx.text("This component only re-renders when props change!"),
36+
rx.divider(),
37+
)
38+
39+
# Use the memoized component in your app
40+
def index():
41+
return rx.vstack(
42+
rx.heading("Memo Example"),
43+
rx.text("Count: 0"), # This will update with state.count
44+
rx.button("Increment", on_click=DemoState.increment),
45+
rx.divider(),
46+
expensive_component(label="Memoized Component"), # Must use keyword arguments
47+
spacing="4",
48+
padding="4",
49+
border_radius="md",
50+
border="1px solid #eaeaea",
51+
)
52+
```
53+
54+
In this example, the `expensive_component` will only re-render when the `label` prop changes, not when the `count` state changes.
55+
56+
## With Event Handlers
57+
58+
You can also use `rx.memo` with components that have event handlers:
59+
60+
```python
61+
# Define a state class to track clicks
62+
class ButtonState(rx.State):
63+
clicks: int = 0
64+
65+
@rx.event
66+
def increment(self):
67+
self.clicks += 1
68+
69+
# Define a memoized button component
70+
@rx.memo
71+
def my_button(text: str, on_click: rx.EventHandler) -> rx.Component:
72+
return rx.button(text, on_click=on_click)
73+
74+
# Use the memoized button in your app
75+
def index():
76+
return rx.vstack(
77+
rx.text("Clicks: 0"), # This will update with state.clicks
78+
my_button(
79+
text="Click me",
80+
on_click=ButtonState.increment
81+
),
82+
spacing="4",
83+
)
84+
```
85+
86+
## With State Variables
87+
88+
When used with state variables, memoized components will only re-render when the specific state variables they depend on change:
89+
90+
```python
91+
# Define a state class with multiple variables
92+
class AppState(rx.State):
93+
name: str = "World"
94+
count: int = 0
95+
96+
@rx.event
97+
def increment(self):
98+
self.count += 1
99+
100+
@rx.event
101+
def set_name(self, name: str):
102+
self.name = name
103+
104+
# Define a memoized greeting component
105+
@rx.memo
106+
def greeting(name: str) -> rx.Component:
107+
return rx.heading("Hello, " + name) # Will display the name prop
108+
109+
# Use the memoized component with state variables
110+
def index():
111+
return rx.vstack(
112+
greeting(name=AppState.name), # Must use keyword arguments
113+
rx.text("Count: 0"), # Will display the count
114+
rx.button("Increment Count", on_click=AppState.increment),
115+
rx.input(
116+
placeholder="Enter your name",
117+
on_change=AppState.set_name,
118+
value="World", # Will be bound to AppState.name
119+
),
120+
spacing="4",
121+
)
122+
```
123+
124+
## Advanced Event Handler Example
125+
126+
You can also pass arguments to event handlers in memoized components:
127+
128+
```python
129+
# Define a state class to track messages
130+
class MessageState(rx.State):
131+
message: str = ""
132+
133+
@rx.event
134+
def set_message(self, text: str):
135+
self.message = text
136+
137+
# Define a memoized component with event handlers that pass arguments
138+
@rx.memo
139+
def action_buttons(on_action: rx.EventHandler[rx.event.passthrough_event_spec(str)]) -> rx.Component:
140+
return rx.hstack(
141+
rx.button("Save", on_click=on_action("Saved!")),
142+
rx.button("Delete", on_click=on_action("Deleted!")),
143+
rx.button("Cancel", on_click=on_action("Cancelled!")),
144+
spacing="2",
145+
)
146+
147+
# Use the memoized component with event handlers
148+
def index():
149+
return rx.vstack(
150+
rx.text("Status: "), # Will display the message
151+
action_buttons(on_action=MessageState.set_message),
152+
spacing="4",
153+
)
154+
```
155+
156+
## Performance Considerations
157+
158+
Use `rx.memo` for:
159+
- Components with expensive rendering logic
160+
- Components that render the same result given the same props
161+
- Components that re-render too often due to parent component updates
162+
163+
Avoid using `rx.memo` for:
164+
- Simple components where the memoization overhead might exceed the performance gain
165+
- Components that almost always receive different props on re-render

0 commit comments

Comments
 (0)