Experimental memo is !experimental #6517
Conversation
Move the memo/custom-component machinery from ``reflex/experimental/memo.py`` and ``reflex_base.components.component`` into a dedicated ``reflex_base.components.memo`` module and expose it as ``rx.memo``. ``rx.experimental.memo`` becomes a deprecated alias, and the legacy ``CustomComponent`` index path in the compiler is dropped now that all memos declare their library per-file.
Component-returning `@rx._x.memo` functions can now declare `rx.EventHandler[...]` (and bare `rx.EventHandler`) parameters, which compile to destructured JSX prop callbacks and are wired through `EventChain` at the call site. Var-returning memos still reject event handlers. Refactors per-parameter behavior into a `_MemoParamSpec` table keyed by a new `MemoParamKind` enum (VALUE / CHILDREN / REST / EVENT_TRIGGER), so each kind owns its classification, validation, placeholder construction, call-site binding, and JSX signature emission. Adds a `_MemoCallBinding` accumulator so `_post_init` no longer special-cases prop vs. rest vs. event routing.
Add explicit rx.Component return annotations to memoized helpers across docs and internal packages, and narrow arrow_svg_component's class_name to Var[str] now that rx.memo handles the conversion.
Greptile SummaryThis PR graduates the
Confidence Score: 4/5Safe to merge with two minor items addressed: add MemoParam/MemoParamKind to all, and consider call-site validation for omitted required EventHandler props. The promotion is well-structured with thorough unit tests and a clear migration path documented. The two open items are quality-of-life issues that don't affect compilation correctness on the happy path, which is fully exercised by the test suite. The legacy CustomComponent removal is complete and consistent across all call sites. packages/reflex-base/src/reflex_base/components/memo.py — the all list and bind* silent-skip behaviour warrant a second look before stabilising the public API surface. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["@rx.memo(fn)"] --> B{Return annotation?}
B -->|rx.Component| C[_create_component_definition]
B -->|rx.Var| D[_create_function_definition]
B -->|other / missing| E[TypeError]
C --> F[_analyze_params for_component=True]
D --> G[_analyze_params for_component=False]
F --> H{Per param: _classify_parameter}
G --> H
H -->|REST| I[MemoParamKind.REST]
H -->|CHILDREN| J[MemoParamKind.CHILDREN]
H -->|EVENT_TRIGGER| K[MemoParamKind.EVENT_TRIGGER]
H -->|VALUE| L[MemoParamKind.VALUE]
C --> M[_register_memo_definition]
D --> M
M --> N[EXPERIMENTAL_MEMOS dict]
N --> O[compile_memo_components]
O --> P[Per-memo .jsx module]
O --> Q[Empty index.jsx]
subgraph Call Site
R["wrapper(*children, **kwargs)"] --> S[_MemoCallBinding]
S --> T{bind_call_value per param}
T -->|VALUE| U[_props dict camelCase]
T -->|EVENT_TRIGGER| V[_event_triggers dict]
T -->|CHILDREN/REST| W[pass-through to Component._post_init]
U --> X[ExperimentalMemoComponent]
V --> X
W --> X
end
|
| for param in params: | ||
| placeholder = _placeholder_for_param(param) | ||
| if param.kind in ( | ||
| placeholder = param.make_placeholder() | ||
| if param.parameter_kind in ( | ||
| inspect.Parameter.POSITIONAL_ONLY, | ||
| inspect.Parameter.POSITIONAL_OR_KEYWORD, | ||
| ): |
There was a problem hiding this comment.
No validation for missing required props at call site
_bind_value and _bind_event_trigger both silently no-op when the caller omits a declared parameter (if param.name in binding.raw_kwargs). For EVENT_TRIGGER params this is particularly sharp: defaults are explicitly rejected by _validate_event_trigger, making the param semantically required, yet omitting it at the call site produces no Python-level error. The missing prop becomes an undefined JS variable inside the rendered JSX, visible only as a broken interaction in the browser. Adding a param.default is inspect.Parameter.empty check before skipping — and raising TypeError when the param is required — would surface the mistake at the Python call site.
Restore reflex/experimental/memo.py as a thin module redirect to reflex_base.components.memo so existing rx.experimental.memo imports keep working with a deprecation warning.
Rename ExperimentalMemo* classes, EXPERIMENTAL_MEMOS registry, and related helpers/tests to plain Memo*/MEMOS now that memo is no longer experimental. Move integration and unit tests out of experimental/ to mirror the new module location.
…efaults Reusable Var-typed empty-value constants so memo signatures can spell strict defaults without per-call-site `Var.create(...)` (which trips B008) or bespoke module-level singletons. Updates the memo doc and the in-tree memos that previously rolled their own empty Var.
26b85b1 to
d5650cf
Compare
All Submissions:
Type of change
Please delete options that are not relevant.
New Feature Submission:
Changes To Core Features:
fixes ENG-9486