Skip to content

Commit fb19fb4

Browse files
authored
ENG-8034: fix window events inside of memoization leaf (#5899)
1 parent 49dacfa commit fb19fb4

File tree

2 files changed

+31
-10
lines changed

2 files changed

+31
-10
lines changed

pyi_hashes.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"reflex/components/core/html.pyi": "86eb9d4c1bb4807547b2950d9a32e9fd",
2121
"reflex/components/core/sticky.pyi": "cb763b986a9b0654d1a3f33440dfcf60",
2222
"reflex/components/core/upload.pyi": "6dc28804a6dddf903e31162e87c1b023",
23-
"reflex/components/core/window_events.pyi": "76bf03a273a1fbbb3b333e10d5d08c30",
23+
"reflex/components/core/window_events.pyi": "af33ccec866b9540ee7fbec6dbfbd151",
2424
"reflex/components/datadisplay/__init__.pyi": "52755871369acbfd3a96b46b9a11d32e",
2525
"reflex/components/datadisplay/code.pyi": "b86769987ef4d1cbdddb461be88539fd",
2626
"reflex/components/datadisplay/dataeditor.pyi": "35391d4ba147cf20ce4ac7a782066d61",

reflex/components/core/window_events.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
"""Window event listener component for Reflex."""
22

3+
from __future__ import annotations
4+
5+
from typing import Any, cast
6+
37
import reflex as rx
48
from reflex.components.base.fragment import Fragment
9+
from reflex.components.component import StatefulComponent, field
510
from reflex.constants.compiler import Hooks
611
from reflex.event import key_event, no_args_event_spec
712
from reflex.vars.base import Var, VarData
@@ -61,6 +66,23 @@ class WindowEventListener(Fragment):
6166
on_popstate: rx.EventHandler[no_args_event_spec]
6267
on_storage: rx.EventHandler[_on_storage_spec]
6368

69+
hooks: list[str] = field(default_factory=list, is_javascript_property=False)
70+
71+
@classmethod
72+
def create(cls, **props) -> WindowEventListener:
73+
"""Create a WindowEventListener component.
74+
75+
Args:
76+
**props: The props to set on the component.
77+
78+
Returns:
79+
The created component.
80+
"""
81+
real_component = cast("WindowEventListener", super().create(**props))
82+
hooks = StatefulComponent._fix_event_triggers(real_component)
83+
real_component.hooks = hooks
84+
return real_component
85+
6486
def _exclude_props(self) -> list[str]:
6587
"""Exclude event handler props from being passed to Fragment.
6688
@@ -69,31 +91,30 @@ def _exclude_props(self) -> list[str]:
6991
"""
7092
return [*super()._exclude_props(), *self.event_triggers.keys()]
7193

72-
def add_hooks(self) -> list[str | Var[str]]:
94+
def add_hooks(self) -> list[str | Var[Any]]:
7395
"""Add hooks to register window event listeners.
7496
7597
Returns:
7698
The hooks to add to the component.
7799
"""
78-
hooks = []
100+
hooks: list[str | Var[Any]] = [*self.hooks]
79101

80102
for prop_name, event_trigger in self.event_triggers.items():
81103
# Get JS event name: remove on_ prefix and underscores
82104
event_name = prop_name.removeprefix("on_").replace("_", "")
83105

84106
hook_expr = f"""
85-
useEffect(() => {{
86-
if (typeof window === 'undefined') return;
87-
88-
window.addEventListener('{event_name}', {event_trigger});
89-
return () => window.removeEventListener('{event_name}', {event_trigger});
90-
}}, []);
107+
useEffect(() => {{
108+
if (typeof window === 'undefined') return;
109+
const fn = {Var.create(event_trigger)};
110+
window.addEventListener('{event_name}', fn);
111+
return () => window.removeEventListener('{event_name}', fn);
112+
}}, []);
91113
"""
92114

93115
hooks.append(
94116
Var(
95117
hook_expr,
96-
_var_type="str",
97118
_var_data=VarData(position=Hooks.HookPosition.POST_TRIGGER),
98119
)
99120
)

0 commit comments

Comments
 (0)