Replies: 1 comment
-
How to Get Viewport in JSThe viewport dimensions can be accessed in javascript via the How to Get Viewport in ReflexUsing a custom react hook, we can register a reflex state Custom Reflex ComponentEdit: updated to work with Reflex 0.5.0+
Define class ResizeWatcher(rx.Fragment):
"""
A component that watches the window size and updates the state.
The only event trigger in `on_resize` which is called once when the component mounts
and again each time the viewport dimensions change.
"""
on_resize: rx.EventHandler[lambda width, height: [width, height]]
def _exclude_props(self) -> list[str]:
return ["on_resize"] Defining def add_imports(self) -> dict[str, str]:
return {"react": "useEffect"}
def add_hooks(self) -> list[str]:
"""Register backend on_resize as a handler for the browser window resize event."""
on_resize = self.event_triggers["on_resize"]
if isinstance(on_resize, rx.EventChain):
on_resize = rx.utils.format.wrap(
rx.utils.format.format_prop(on_resize).strip("{}"),
"(",
)
return [
"""
useEffect(() => {
function handleResize() {
%s(window.innerWidth, window.innerHeight);
}
// Fire initial resize event when the component mounts.
handleResize();
// Add the event listener with cleanup.
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);""" % (
on_resize,
)
] This is a critical line Define Event Handler and StateFirst define some attributes that we will render in the frontend. class State(rx.State):
viewport_width: int = 0
viewport_height: int = 0
device: str = "undetermined" Then define the event handler that will be called when the def set_viewport(self, width: int, height: int) -> None:
self.viewport_width = width
self.viewport_height = height
self.device = device_guess(width) Putting it all togetherDemo 📼Screen.Recording.2024-01-25.at.9.25.54.PM.movfrom typing import Any
import reflex as rx
def device_guess(width: int) -> str:
if width < 520:
return "phone"
elif width < 768:
return "phone-landscape"
elif width < 1024:
return "tablet"
elif width < 1280:
return "tablet-landscape"
elif width < 1640:
return "laptop"
else:
return "desktop"
class State(rx.State):
viewport_width: int = 0
viewport_height: int = 0
device: str = "undetermined"
def set_viewport(self, width: int, height: int) -> None:
self.viewport_width = width
self.viewport_height = height
self.device = device_guess(width)
class ResizeWatcher(rx.Fragment):
"""
A component that watches the window size and updates the state.
The only event trigger in `on_resize` which is called once when the component mounts
and again each time the viewport dimensions change.
"""
on_resize: rx.EventHandler[lambda width, height: [width, height]]
def _exclude_props(self) -> list[str]:
return ["on_resize"]
def add_imports(self) -> dict[str, str]:
return {"react": "useEffect"}
def add_hooks(self) -> list[str]:
"""Register backend on_resize as a handler for the browser window resize event."""
on_resize = self.event_triggers["on_resize"]
if isinstance(on_resize, rx.EventChain):
on_resize = rx.utils.format.wrap(
rx.utils.format.format_prop(on_resize).strip("{}"),
"(",
)
return [
"""
useEffect(() => {
function handleResize() {
%s(window.innerWidth, window.innerHeight);
}
// Fire initial resize event when the component mounts.
handleResize();
// Add the event listener with cleanup.
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);""" % (
on_resize,
)
]
def index() -> rx.Component:
return rx.vstack(
ResizeWatcher.create(on_resize=State.set_viewport),
rx.heading("Viewport Resize Watcher Demo"),
rx.heading(f"[{State.viewport_width}, {State.viewport_height}]"),
rx.heading(f"Device: {State.device}"),
align="center",
font_size="2em",
padding_top="10%",
)
app = rx.App()
app.add_page(index) |
Beta Was this translation helpful? Give feedback.
-
Reflex does not have some
on_resize
event, how can we update state when the viewport is resized?Beta Was this translation helpful? Give feedback.
All reactions