Skip to content

Commit f2e4e5a

Browse files
fix: Preserve event_actions from @rx.event decorator in mixin event handlers (reflex-dev#6099)
* fix: Preserve event_actions from @rx.event decorator in mixin event handlers * add constant
1 parent 9201f0e commit f2e4e5a

3 files changed

Lines changed: 23 additions & 2 deletions

File tree

reflex/event.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def substate_token(self) -> str:
8989
_EVENT_FIELDS: set[str] = {f.name for f in dataclasses.fields(Event)}
9090

9191
BACKGROUND_TASK_MARKER = "_reflex_background_task"
92+
EVENT_ACTIONS_MARKER = "_rx_event_actions"
9293

9394

9495
@dataclasses.dataclass(
@@ -2311,6 +2312,7 @@ class EventNamespace:
23112312

23122313
# Constants
23132314
BACKGROUND_TASK_MARKER = BACKGROUND_TASK_MARKER
2315+
EVENT_ACTIONS_MARKER = EVENT_ACTIONS_MARKER
23142316
_EVENT_FIELDS = _EVENT_FIELDS
23152317
FORM_DATA = FORM_DATA
23162318
upload_files = upload_files
@@ -2461,7 +2463,7 @@ def wrapper(
24612463
# Store decorator event actions on the function for later processing
24622464
event_actions = _build_event_actions()
24632465
if event_actions:
2464-
func._rx_event_actions = event_actions # pyright: ignore [reportFunctionMemberAccess]
2466+
setattr(func, EVENT_ACTIONS_MARKER, event_actions)
24652467
return func # pyright: ignore [reportReturnType]
24662468

24672469
if func is not None:

reflex/state.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from reflex.environment import PerformanceMode, environment
4343
from reflex.event import (
4444
BACKGROUND_TASK_MARKER,
45+
EVENT_ACTIONS_MARKER,
4546
Event,
4647
EventHandler,
4748
EventSpec,
@@ -753,6 +754,9 @@ def _copy_fn(fn: Callable) -> Callable:
753754
newfn.__annotations__ = fn.__annotations__
754755
if mark := getattr(fn, BACKGROUND_TASK_MARKER, None):
755756
setattr(newfn, BACKGROUND_TASK_MARKER, mark)
757+
# Preserve event_actions from @rx.event decorator
758+
if event_actions := getattr(fn, EVENT_ACTIONS_MARKER, None):
759+
object.__setattr__(newfn, EVENT_ACTIONS_MARKER, event_actions)
756760
return newfn
757761

758762
@staticmethod
@@ -1255,7 +1259,7 @@ def _create_event_handler(
12551259
The event handler.
12561260
"""
12571261
# Check if function has stored event_actions from decorator
1258-
event_actions = getattr(fn, "_rx_event_actions", {})
1262+
event_actions = getattr(fn, EVENT_ACTIONS_MARKER, {})
12591263

12601264
return event_handler_cls(
12611265
fn=fn, state_full_name=cls.get_full_name(), event_actions=event_actions

tests/units/test_state.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3737,6 +3737,21 @@ def test_bare_mixin_state() -> None:
37373737
assert ChildBareMixinState.get_root_state() == State
37383738

37393739

3740+
def test_mixin_event_handler_preserves_event_actions() -> None:
3741+
"""Test that event_actions from @rx.event decorator are preserved when inherited from mixins."""
3742+
3743+
class EventActionsMixin(BaseState, mixin=True):
3744+
@rx.event(prevent_default=True, stop_propagation=True)
3745+
def handle_with_actions(self):
3746+
pass
3747+
3748+
class UsesEventActionsMixin(EventActionsMixin, State):
3749+
pass
3750+
3751+
handler = UsesEventActionsMixin.handle_with_actions
3752+
assert handler.event_actions == {"preventDefault": True, "stopPropagation": True}
3753+
3754+
37403755
def test_assignment_to_undeclared_vars():
37413756
"""Test that an attribute error is thrown when undeclared vars are set."""
37423757

0 commit comments

Comments
 (0)