|
| 1 | +```python exec |
| 2 | +import reflex as rx |
| 3 | + |
| 4 | +from pcweb.templates.docpage import docdemo, h1_comp, text_comp, docpage |
| 5 | + |
| 6 | +def basic_example(): |
| 7 | + @rx.memo |
| 8 | + def memoized_component(text_var: rx.Var[str]) -> rx.Component: |
| 9 | + return rx.text(text_var) |
| 10 | + |
| 11 | + class MemoState(rx.State): |
| 12 | + count: int = 0 |
| 13 | + text: str = "This component is memoized and won't re-render when the counter changes." |
| 14 | + |
| 15 | + def increment(self): |
| 16 | + self.count += 1 |
| 17 | + |
| 18 | + return rx.vstack( |
| 19 | + rx.hstack( |
| 20 | + rx.button("Increment Counter", on_click=MemoState.increment), |
| 21 | + rx.text(f"Count: {MemoState.count}"), |
| 22 | + ), |
| 23 | + memoized_component(MemoState.text), |
| 24 | + spacing="4", |
| 25 | + ) |
| 26 | + |
| 27 | +def recursive_example(): |
| 28 | + class RecursiveState(rx.State): |
| 29 | + depth: int = 3 |
| 30 | + |
| 31 | + def increase_depth(self): |
| 32 | + self.depth += 1 |
| 33 | + |
| 34 | + def decrease_depth(self): |
| 35 | + if self.depth > 0: |
| 36 | + self.depth -= 1 |
| 37 | + |
| 38 | + @rx.memo |
| 39 | + def recursive_component(depth: rx.Var[int]) -> rx.Component: |
| 40 | + return rx.cond( |
| 41 | + depth <= 0, |
| 42 | + rx.text("Reached bottom!"), |
| 43 | + rx.vstack( |
| 44 | + rx.text(f"Depth: {depth}"), |
| 45 | + recursive_component(depth - 1), |
| 46 | + border="1px solid #eaeaea", |
| 47 | + padding="1em", |
| 48 | + border_radius="0.5em", |
| 49 | + ) |
| 50 | + ) |
| 51 | + |
| 52 | + return rx.vstack( |
| 53 | + rx.hstack( |
| 54 | + rx.button("Increase Depth", on_click=RecursiveState.increase_depth), |
| 55 | + rx.button("Decrease Depth", on_click=RecursiveState.decrease_depth), |
| 56 | + ), |
| 57 | + recursive_component(RecursiveState.depth), |
| 58 | + spacing="4", |
| 59 | + ) |
| 60 | + |
| 61 | +def event_handler_example(): |
| 62 | + class EventState(rx.State): |
| 63 | + clicked: bool = False |
| 64 | + |
| 65 | + def toggle(self): |
| 66 | + self.clicked = not self.clicked |
| 67 | + |
| 68 | + @rx.memo |
| 69 | + def memoized_with_event(handler) -> rx.Component: |
| 70 | + return rx.button( |
| 71 | + "Click Me", |
| 72 | + on_click=handler, |
| 73 | + color=rx.cond(EventState.clicked, "green", "blue"), |
| 74 | + ) |
| 75 | + |
| 76 | + return rx.vstack( |
| 77 | + rx.text(f"Button clicked: {EventState.clicked}"), |
| 78 | + memoized_with_event(EventState.toggle), |
| 79 | + spacing="4", |
| 80 | + ) |
| 81 | +``` |
| 82 | + |
| 83 | +# Memoization with rx.memo |
| 84 | + |
| 85 | +The `rx.memo` decorator is used to memoize components in Reflex applications. Memoization is a performance optimization technique that prevents unnecessary re-renders of components when their inputs haven't changed. |
| 86 | + |
| 87 | +## Basic Usage |
| 88 | + |
| 89 | +Use the `@rx.memo` decorator on component functions to memoize them: |
| 90 | + |
| 91 | +```python |
| 92 | +@rx.memo |
| 93 | +def my_component(text: rx.Var[str]) -> rx.Component: |
| 94 | + return rx.text(text) |
| 95 | +``` |
| 96 | + |
| 97 | +When a component is memoized, Reflex will only re-render it when its inputs (props) change. This can significantly improve performance in complex applications with many components. |
| 98 | + |
| 99 | +```python eval |
| 100 | +basic_example() |
| 101 | +``` |
| 102 | + |
| 103 | +## Benefits of Memoization |
| 104 | + |
| 105 | +- **Performance Optimization**: Prevents unnecessary re-renders when component props haven't changed |
| 106 | +- **Reduced Computation**: Avoids expensive calculations when inputs remain the same |
| 107 | +- **Smoother UI**: Helps maintain responsive user interfaces in complex applications |
| 108 | + |
| 109 | +## Advanced Usage |
| 110 | + |
| 111 | +### Recursive Components |
| 112 | + |
| 113 | +The `rx.memo` decorator supports recursive UI elements, allowing you to create components that reference themselves: |
| 114 | + |
| 115 | +```python eval |
| 116 | +recursive_example() |
| 117 | +``` |
| 118 | + |
| 119 | +### Components with Event Handlers |
| 120 | + |
| 121 | +You can pass event handlers as arguments to memoized components: |
| 122 | + |
| 123 | +```python eval |
| 124 | +event_handler_example() |
| 125 | +``` |
| 126 | + |
| 127 | +## When to Use Memoization |
| 128 | + |
| 129 | +Memoization is most beneficial in the following scenarios: |
| 130 | + |
| 131 | +1. **Complex Components**: When components perform expensive calculations or rendering |
| 132 | +2. **Deeply Nested Components**: When components are deep in the component tree and re-render frequently |
| 133 | +3. **Components with Stable Props**: When components receive props that rarely change |
| 134 | + |
| 135 | +## Implementation Details |
| 136 | + |
| 137 | +Under the hood, `rx.memo` works by: |
| 138 | + |
| 139 | +1. Comparing the current props with previous props |
| 140 | +2. Skipping the re-render if all props are the same |
| 141 | +3. Re-rendering only when props have changed |
| 142 | + |
| 143 | +This optimization helps maintain application performance as your Reflex app grows in complexity. |
0 commit comments