Hoist usePollSubscriptions to RoomWidgetsView; drop the side effect from usePollWidget

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.
This commit is contained in:
simoleo89
2026-05-11 16:36:11 +00:00
parent 7218285583
commit 419de09638
2 changed files with 14 additions and 14 deletions
@@ -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>(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<RoomEngineObjectEvent>(
+8 -13
View File
@@ -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();