Reactive Decorators¶
TL;DR — Decorators that let you control precisely how and when reactive code executes.
Problem¶
When you write reactive UI code, you quickly face challenges:
- A value changes 10 times in 100ms → 10 recomputations instead of 1
- User search triggers an API request on every keystroke
- An effect function subscribes 50 times to the same event
- Code runs even when its conditions no longer apply
Solution¶
FletX provides a toolkit of decorators that factorize recurring patterns. Use them to debounce, throttle, memoize, batch, filter, and structure your reactive effects.
Progression: simple → advanced¶
We'll progress from simple use cases (5 min) to sophisticated patterns (20 min). All examples use real APIs from fletx/decorators/*.
1. Batch updates: @reactive_batch()¶
When to use it: You mutate an RxList or multiple Reactive values in quick succession, and you want one UI update instead of many.
Example:
Tip: Keep refresh_ui() small and without heavy side effects. It's just a grouper.
2. Wait for a pause: @reactive_debounce(delay)¶
When to use it: User input (search box), API calls, heavy computations triggered by the user.
Example:
Tip: Use 0.3–0.5s for user input, 1–2s for heavy computation. Don't abuse long delays in critical flows.
3. Limit frequency: @reactive_throttle(interval)¶
When to use it: Scroll, resize, high-frequency events. You want to execute at most once per interval.
Example:
| Python | |
|---|---|
Tip: Throttle maintains responsiveness (fast execution), whereas debounce waits for inactivity.
4. Execute only if: @reactive_when(condition)¶
When to use it: A flag enables/disables behavior. Feature flags, admin mode, permissions.
Example:
| Python | |
|---|---|
Tip: The condition can be a callable or a Reactive[bool].
5. Observe selectively: @reactive_select(*reactive_props)¶
When to use it: An object has many properties. You only want to react to certain ones.
Example:
Tip: Reduces unnecessary recomputations when a state has many properties.
6. Pure derivations: @reactive_computed(deps=None)¶
When to use it: Create a reactive value computed from other reactives.
Example:
| Python | |
|---|---|
Tip: The function must be pure (no side effects). FletX automatically caches the result as long as dependencies don't change.
7. Cache computations: @reactive_memo(maxsize=64, key_fn=None)¶
When to use it: An expensive function called multiple times with the same arguments.
Example:
Tip: Provide key_fn if your arguments are complex.
8. Run side effects: @reactive_effect(deps=None, auto_run=True) and use_effect(effect_fn, deps)¶
When to use it: Timers, sockets, subscriptions, DOM modifications, non-GET API calls.
Example 1 — reactive_effect declarative:
| Python | |
|---|---|
Example 2 — use_effect in a builder:
| Python | |
|---|---|
Tip: Always return a cleanup function if you open external resources (timers, sockets, subscriptions). FletX calls it when the component is destroyed.
9. Reactive builder: @obx (from fletx/decorators/widgets.py)¶
When to use it: Create a widget that rebuilds reactively when its dependencies change — but preserves widget identity in the tree.
Example:
Tip: FletX automatically detects all reads of Reactive during the build. No need to list dependencies.
10. Reusable reactive controls¶
10.1. Bind a property: @reactive_control(), @simple_reactive(), @two_way_reactive()¶
When to use it: You're creating a reusable widget and want its properties to sync with reactives.
Example — simple binding:
Example — two-way binding:
| Python | |
|---|---|
10.2. Computed properties: @computed_reactive()¶
Example:
10.3. Reactive lists: @reactive_list()¶
When to use it: You have an RxList and want it to render automatically.
Example:
10.4. Forms: @reactive_form()¶
When to use it: You're building a form with validations and a submit handler.
Example:
10.5. State machine: @reactive_state_machine()¶
When to use it: A widget has multiple states (idle, loading, error, success) and transitions between them.
Example:
Complete example: search engine¶
Best practices (summary)¶
| Problem | Solution |
|---|---|
| Too many updates | @reactive_batch() or group mutations |
| User search + API calls | @reactive_debounce() |
| Scroll/resize high frequency | @reactive_throttle() |
| Function called often with same arg | @reactive_memo() |
| Complex condition for execution | @reactive_when() |
| Pure derived value | @reactive_computed() |
| Effects (timers, sockets) | @reactive_effect() or use_effect() |
| Widget that reacts to changes | @obx |
| Reusable control | @reactive_control, @reactive_form, @reactive_list |
Common pitfalls¶
- Not cleaning up effects → memory leaks. Always return a cleanup function.
- Keeping cache too long → stale data. Prefer small
maxsize. - Too aggressive debounce → user waits. Stay under 500ms.
- Forgetting that
computedauto-caches → no need for memo if you useComputed. - Mixing computation and effects → hard to test. Keep them separate.
References¶
fletx/decorators/reactive.py— batch, memo, debounce, throttle, when, select, effect, computedfletx/decorators/effects.py— use_effectfletx/decorators/widgets.py— obx, reactive_control, reactive_form, reactive_list, reactive_state_machine
See also:
- Controllers — how to structure your reactive logic
- State Management — understand
RxInt,RxList,Computed - Pages — integrate decorators and pages into your app
Ready to try? Start with @reactive_debounce() on a search box. It's the most common use case!