fix(reflex): stream on_view_change during gestures with a latest-wins throttle#201
Conversation
… throttle PR #113 replaced the wrapper's immediate on_view_change dispatch with a 200 ms trailing-edge debounce. A continuous pan/zoom emits a view_change per animation frame, so the timer reset on every frame and the handler could only fire after the gesture went quiet — an on_view_change-computed detail chart froze until the interaction ended instead of tracking it live (demo section 4). Replace the debounce with a leading+trailing latest-wins throttle (VIEW_THROTTLE_MS = 120, matching hover): the first event of a gesture dispatches immediately, updates stream at most once per window while it is in progress, and the trailing flush guarantees the resting viewport always lands last. The envelope's phase field now reflects the client's gesture phase — "update" mid-gesture, "final" at rest — so handlers that only want settled views can filter on it; linked/republish suppression and unmount cleanup are unchanged. Verified against the running showcase app with a CDP probe: 24 wheel steps at 140 ms spacing produced 23 mid-gesture Reflex state updates (the old debounce produces none), with the exact resting view arriving as the final event. Spec (reflex-integration.md), ViewChangeEvent typing/docstring, README, demo comment, and the wrapper contract test updated to pin the new behavior.
Merging this PR will not alter performance
Comparing Footnotes
|
Greptile SummaryThis PR streams Reflex viewport changes during active gestures. The main changes are:
Confidence Score: 5/5This looks safe to merge. No blocking issues found in the changed code. The client terminal phase is mapped to Unmount cleanup clears the timer and pending event.
What T-Rex did
Important Files Changed
Reviews (1): Last reviewed commit: "fix(reflex): stream on_view_change durin..." | Re-trigger Greptile |
masenf
left a comment
There was a problem hiding this comment.
do the reflex built-in throttle and debounce event actions not work with this event? if the event debouncing is only in the reflex wrapper, do we need to re-implement this functionality in a way that is not configurable by the developer?
Problem
PR #113 replaced the Reflex wrapper's immediate
on_view_changedispatch with a 200 ms trailing-edge debounce. The render client emits aview_changeper animation frame during a pan/zoom, so every frame reset the timer — the handler could only fire once the gesture went quiet. Anon_view_change-computed detail chart (showcase §4) froze during the interaction and only re-rendered ~a second after it ended, where it previously tracked the gesture in real time.Fix
dispatchViewinXYChart.jsxnow uses a leading + trailing, latest-wins throttle (VIEW_THROTTLE_MS = 120, matching the hover throttle):The envelope's
phasefield now reflects the client's gesture phase —"update"mid-gesture,"final"at rest — so handlers that only care about settled views can filter on it.linked/republishsource suppression and unmount timer cleanup are unchanged. Handlers written against the old contract keep working: they simply receive intermediateupdateevents before the samefinalone.Verification
phase: "final") arriving last.scripts/reflex_ws_smoke.pymount/shared-websocket/pixel assertions pass. Its §16 density-drill step times out, but it fails identically with the unmodified mainXYChart.jsxswapped into the served app — pre-existing on main, unrelated to this change (tracked separately).pre-commit run --all-files,ruff check,ruff format --checkall green; the wrapper contract test assertions replayed against the modified JSX all hold.Spec
Per the spec-first contract:
spec/design/reflex-integration.mdnow documents the throttle + phase stream (and drops a stale line-number cite),ViewChangeEventtyping/docstring,python/reflex-xy/README.md, the demo comment, andtests/reflex_adapter/test_component.pyare updated to pin the new behavior.