fix(event): handle mixed rx.cond event/function returns in event lambdas#6354
fix(event): handle mixed rx.cond event/function returns in event lambdas#6354BABTUNA wants to merge 2 commits intoreflex-dev:mainfrom
Conversation
Greptile SummaryThis PR fixes Confidence Score: 5/5Safe to merge — the fix is correct and all remaining findings are P2 style/quality suggestions that do not block the primary use case. No P0 or P1 findings. The over-broad type guard and missing event_actions propagation are both P2: the former is harmless in practice, and the latter is consistent with pre-existing FunctionVar behavior rather than a regression. packages/reflex-base/src/reflex_base/event/init.py — the new type guard condition and hard-coded event_actions warrant a second look, but neither blocks merge. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["call_event_fn(fn, arg_spec)"] --> B["Invoke fn with parsed args"]
B --> C["Normalize to list: out = [...]"]
C --> D["For each e in out"]
D --> E{"isinstance(e, EventHandler)?"}
E -- Yes --> F["call_event_handler(e, ...)"]
E -- No --> G{"isinstance(e, EventChain)?"}
F --> G
G -- Yes --> H["e = Var.create(e)"]
G -- No --> I{"isinstance(e, Var) and\nnot EventVar/FunctionVar and\ntypehint_issubclass(type, EventSpec|Callable)?"}
H --> I
I -- Yes --> J["_dispatch_mixed_event_var(e)\n→ JS arrow fn with typeof branch"]
I -- No --> K{"isinstance(e, EventSpec|FunctionVar|EventVar)?"}
J --> K
K -- No --> L["Raise EventHandlerValueError"]
K -- Yes --> M["events.append(e)"]
M --> D
J --> N["JS: (...args) => {\n const __event_or_fn = ...;\n if (typeof __event_or_fn === 'function')\n return __event_or_fn(...args);\n return addEvents([__event_or_fn], args, {});\n}"]
Reviews (1): Last reviewed commit: "Handle mixed rx.cond event/function retu..." | Re-trigger Greptile |
| f'if (typeof {event_like_name} === "function") {{' | ||
| f"return {event_like_name}(...args);" | ||
| "}" | ||
| f"return {CompileVars.ADD_EVENTS}([{event_like_name}], args, ({{ }}));" |
There was a problem hiding this comment.
Chain-level
event_actions not propagated to conditional backend events
_dispatch_mixed_event_var hard-codes ({ }) (an empty object) as the event_actions argument to addEvents. If this dispatcher ends up in an EventChain carrying chain-level event_actions (e.g. preventDefault: True), those actions will be silently dropped for any conditional branch that resolves to a backend event. The existing EventVar→invocation.call(...) path threads those actions correctly, but the new FunctionVar wrapper bypasses that path. This is consistent with pre-existing FunctionVar behavior (not a regression), but worth noting for future callers.
There was a problem hiding this comment.
bit out of the scope of this PR imo
| f'if (typeof {event_like_name} === "function") {{' | ||
| f"return {event_like_name}(...args);" | ||
| "}" | ||
| f"return {CompileVars.ADD_EVENTS}([{event_like_name}], args, ({{ }}));" |
There was a problem hiding this comment.
Extraneous spaces in empty object literal
({{ }}) produces ({ }) — a parenthesised empty object with two interior spaces — in the emitted JavaScript. This is valid but inconsistent with idiomatic {}. Consider {{}} instead.
| f"return {CompileVars.ADD_EVENTS}([{event_like_name}], args, ({{ }}));" | |
| f"return {CompileVars.ADD_EVENTS}([{event_like_name}], args, ({{}}));" |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
@masenf plz review when you get a chance 🙏🙏🙏 |
masenf
left a comment
There was a problem hiding this comment.
since this behavior is very dependent on how the generated code actually works, we need to see an integration test (or extend an existing integration test) that exercises this behavior end to end.
| return Var( | ||
| _js_expr=( | ||
| "(...args) => {" | ||
| f"const {event_like_name} = {event_like_var!s};" | ||
| f'if (typeof {event_like_name} === "function") {{' | ||
| f"return {event_like_name}(...args);" | ||
| "}" | ||
| f"return {CompileVars.ADD_EVENTS}([{event_like_name}], args, ({{}}));" | ||
| "}" | ||
| ), | ||
| _var_type=Callable, | ||
| _var_data=VarData.merge( | ||
| event_like_var._get_all_var_data(), | ||
| VarData( | ||
| imports=Imports.EVENTS, | ||
| hooks={Hooks.EVENTS: None}, | ||
| ), | ||
| ), | ||
| ).to(FunctionVar) |
There was a problem hiding this comment.
prefer to use ArgsFunctionOperations.create helper with rest and explicit_return arguments.
using a structured Var is helpful because it allows the compiler to optimize the form down the road without changing user-facing code and it tends to be less brittle w.r.t composition, carry var data, etc.
All Submissions:
github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) file?
Requests for the desired
changed?
Type of change
New Feature Submission:
Changes To Core Features:
like us to include them?
Description
This fixes event-lambda handling for
rx.cond(...)expressions that returnmixed event-like values (frontend function branch vs backend event branch).
Before this change,
call_event_fnrejected this pattern because thelambda return was a
Var(CustomVarOperation) rather than one of:EventSpecEventHandlerEventVarFunctionVarThat made valid mixed conditional handlers fail during event-chain
creation.
handles issue #6204