From f948a8f798d9dce51c3ea035adf41a98a2e68f92 Mon Sep 17 00:00:00 2001 From: Germain Date: Thu, 31 Aug 2023 14:36:47 +0100 Subject: [PATCH] Update member count on room summary update (#11488) * Update member count on room summary update * Fix performance regression for large rooms * Update useRoomMemberCount JSDoc * Improve throttle updates definition * remove useCallback --- src/hooks/room/useRoomCallStatus.ts | 2 +- src/hooks/useRoomMembers.ts | 60 +++++++++++++---------------- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/hooks/room/useRoomCallStatus.ts b/src/hooks/room/useRoomCallStatus.ts index 1f96395a35..7afd1f9ce4 100644 --- a/src/hooks/room/useRoomCallStatus.ts +++ b/src/hooks/room/useRoomCallStatus.ts @@ -67,7 +67,7 @@ export const useRoomCallStatus = ( const hasGroupCall = useCall(room.roomId) !== null; - const memberCount = useRoomMemberCount(room, { includeFunctional: false }); + const memberCount = useRoomMemberCount(room); const [mayEditWidgets, mayCreateElementCalls] = useTypedEventEmitterState( room, diff --git a/src/hooks/useRoomMembers.ts b/src/hooks/useRoomMembers.ts index b9db87bc2d..f054d7337b 100644 --- a/src/hooks/useRoomMembers.ts +++ b/src/hooks/useRoomMembers.ts @@ -14,12 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { Room, RoomEvent, RoomMember, RoomStateEvent } from "matrix-js-sdk/src/matrix"; import { throttle } from "lodash"; import { useTypedEventEmitter } from "./useEventEmitter"; -import { getJoinedNonFunctionalMembers } from "../utils/room/getJoinedNonFunctionalMembers"; // Hook to simplify watching Matrix Room joined members export const useRoomMembers = (room: Room, throttleWait = 250): RoomMember[] => { @@ -43,43 +42,38 @@ type RoomMemberCountOpts = { * Wait time between room member count update */ throttleWait?: number; - /** - * Whether to include functional members (bots, etc...) in the room count - * @default true - */ - includeFunctional: boolean; }; -// Hook to simplify watching Matrix Room joined member count -export const useRoomMemberCount = ( - room: Room, - opts: RoomMemberCountOpts = { throttleWait: 250, includeFunctional: true }, -): number => { +/** + * Returns a count of members in a given room + * @param room the room to track. + * @param opts The options. + * @returns the room member count. + */ +export const useRoomMemberCount = (room: Room, opts: RoomMemberCountOpts = { throttleWait: 250 }): number => { const [count, setCount] = useState(room.getJoinedMemberCount()); - const { throttleWait, includeFunctional } = opts; + const { throttleWait } = opts; - useTypedEventEmitter( - room.currentState, - RoomStateEvent.Members, - throttle( - () => { - // At the time where `RoomStateEvent.Members` is emitted the - // summary API has not had a chance to update the `summaryJoinedMemberCount` - // value, therefore handling the logic locally here. - // - // Tracked as part of https://github.com/vector-im/element-web/issues/26033 - const membersCount = includeFunctional - ? room.getMembers().reduce((count, m) => { - return m.membership === "join" ? count + 1 : count; - }, 0) - : getJoinedNonFunctionalMembers(room).length; - setCount(membersCount); - }, - throttleWait, - { leading: true, trailing: true }, - ), + const throttledUpdate = useMemo( + () => + throttle( + () => { + setCount(room.getJoinedMemberCount()); + }, + throttleWait, + { leading: true, trailing: true }, + ), + [room, throttleWait], ); + + useTypedEventEmitter(room.currentState, RoomStateEvent.Members, throttledUpdate); + + /** + * `room.getJoinedMemberCount()` caches the member count behind the room summary + * So we need to re-compute the member count when the summary gets updated + */ + useTypedEventEmitter(room, RoomEvent.Summary, throttledUpdate); return count; };