From 419de0963832ae5325b00d4fdde1ddaf71a6a3f4 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Mon, 11 May 2026 16:36:11 +0000 Subject: [PATCH] Hoist usePollSubscriptions to RoomWidgetsView; drop the side effect from usePollWidget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to the previous commit's poll split. The compat shim usePollWidget used to call usePollSubscriptions() inside its body so the three RoomSessionPollEvent listeners were still registered for existing consumers — but that meant: - listeners would be re-registered per consumer (today nobody, since useWordQuizWidget was already migrated to usePollActions); - the lifetime of the subscriptions was tied to a leaf widget instead of the room session; - a render of a component using the shim had the side effect of attaching three global event listeners. Move - src/components/room/widgets/RoomWidgetsView.tsx now calls usePollSubscriptions() once at the top of the room-widget tree. The bridge from RoomSessionPollEvent (OFFER/ERROR/CONTENT) to the UI event bus is now mounted for exactly the lifetime of an in-room session, regardless of which leaf widget renders. - src/hooks/rooms/widgets/usePollWidget.ts (compat shim) is reduced to a one-liner that just returns usePollActions(). It is still deprecated; remove once nothing imports it. Verification - yarn eslint on the two touched files: 1 pre-existing error (the same FC<{}> in RoomWidgetsView that was there before — baseline unchanged; I deliberately did not touch it in this commit to keep the diff minimal). - yarn test: 22/22 still passing. - grep confirms usePollWidget has zero in-tree consumers; the only importer is the barrel re-export. --- .../room/widgets/RoomWidgetsView.tsx | 7 ++++++- src/hooks/rooms/widgets/usePollWidget.ts | 21 +++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/room/widgets/RoomWidgetsView.tsx b/src/components/room/widgets/RoomWidgetsView.tsx index 7768aa5..66745c2 100644 --- a/src/components/room/widgets/RoomWidgetsView.tsx +++ b/src/components/room/widgets/RoomWidgetsView.tsx @@ -2,7 +2,7 @@ import { GetRoomEngine, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngine import { FC } from 'react'; import { DispatchUiEvent, LocalizeText, NotificationAlertType, RoomWidgetUpdateRoomObjectEvent } from '../../../api'; import { WidgetErrorBoundary } from '../../../common'; -import { useNitroEvent, useNotification, useRoom } from '../../../hooks'; +import { useNitroEvent, useNotification, usePollSubscriptions, useRoom } from '../../../hooks'; import { AvatarInfoWidgetView } from './avatar-info/AvatarInfoWidgetView'; import { ChatInputView } from './chat-input/ChatInputView'; import { ChatWidgetView } from './chat/ChatWidgetView'; @@ -22,6 +22,11 @@ export const RoomWidgetsView: FC<{}> = props => const { roomSession = null } = useRoom(); const { simpleAlert = null } = useNotification(); + // Bridge RoomSessionPollEvent (OFFER/ERROR/CONTENT) onto the UI bus + // for the lifetime of the room session. Single mount point so the + // listeners are not re-registered per widget render. + usePollSubscriptions(); + useNitroEvent(RoomZoomEvent.ROOM_ZOOM, event => GetRoomEngine().setRoomInstanceRenderingCanvasScale(event.roomId, 1, (((event.level)<1) ? 0.5 : (1 << (Math.floor(event.level) - 1))), null, null, event.isFlipForced)); useNitroEvent( diff --git a/src/hooks/rooms/widgets/usePollWidget.ts b/src/hooks/rooms/widgets/usePollWidget.ts index 746ae99..ce1e505 100644 --- a/src/hooks/rooms/widgets/usePollWidget.ts +++ b/src/hooks/rooms/widgets/usePollWidget.ts @@ -1,17 +1,12 @@ import { usePollActions } from './usePollActions'; -import { usePollSubscriptions } from './usePollSubscriptions'; /** - * @deprecated Prefer `usePollSubscriptions` (mount once, top-level) and - * `usePollActions` (anywhere a component dispatches a vote/accept/reject). - * This shim preserves the old `{ startPoll, rejectPoll, answerPoll }` - * shape for existing consumers, but each call also re-mounts the three - * subscription listeners — which is wrong if the hook is called from - * multiple places. + * @deprecated Prefer `usePollActions` for components that dispatch + * votes/accepts/rejects. The corresponding subscriptions are now mounted + * once by `RoomWidgetsView` via `usePollSubscriptions`, so this shim no + * longer needs to register them transitively. + * + * Kept only to preserve the `{ startPoll, rejectPoll, answerPoll }` + * shape for any out-of-tree consumer; remove once nothing imports it. */ -export const usePollWidget = () => -{ - usePollSubscriptions(); - - return usePollActions(); -}; +export const usePollWidget = () => usePollActions();