diff --git a/src/components/viewmodels/right_panel/RoomSummaryCardViewModel.tsx b/src/components/viewmodels/right_panel/RoomSummaryCardViewModel.tsx index 143f3fca18..45018e7e20 100644 --- a/src/components/viewmodels/right_panel/RoomSummaryCardViewModel.tsx +++ b/src/components/viewmodels/right_panel/RoomSummaryCardViewModel.tsx @@ -158,9 +158,9 @@ export function useRoomSummaryCardViewModel( const e2eStatus = roomContext.e2eStatus; const isVideoRoom = calcIsVideoRoom(room); - const roomState = useRoomState(room); - // used to check if the room is public or not - const roomJoinRule = roomState.getJoinRule(); + const { roomJoinRule } = useRoomState(room, (state) => ({ + roomJoinRule: state.getJoinRule(), + })); const alias = room.getCanonicalAlias() || room.getAltAliases()[0] || ""; const pinCount = usePinnedEvents(room).length; // value to check if the user can invite to the room diff --git a/src/hooks/useRoomState.ts b/src/hooks/useRoomState.ts index 5555629bb1..5a0a2d7541 100644 --- a/src/hooks/useRoomState.ts +++ b/src/hooks/useRoomState.ts @@ -12,14 +12,32 @@ import { type Room, type RoomState, RoomStateEvent } from "matrix-js-sdk/src/mat import { useTypedEventEmitter } from "./useEventEmitter"; type Mapper = (roomState: RoomState) => T; -const defaultMapper: Mapper = (roomState: RoomState) => roomState; -// Hook to simplify watching Matrix Room state -// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint -export const useRoomState = ( - room?: Room, - mapper: Mapper = defaultMapper as Mapper, -): T => { +/** + * A hook to watch the state of a room. + * + * Call `useRoomState` in a component to watch the state of a room. + * + * A mapper function must be provided to process the room state into outputs suitable for the component. The mapper + * function will be called whenever the room state changes. + * + * @example + * ``` + * function MyComponent({room}: Props): JSX.Element { + * const { historyVisibility, joinRule } = useRoomState(room, state => ({ + * historyVisibility: state.getHistoryVisibility(), + * joinRule: state.getJoinRule(), + * })); + * // ... + * ``` + * + * @param room - The room to watch. If this is undefined, the returned value will also be undefined. + * @param mapper - A function to process the room state into outputs suitable for the component. + * @returns The output of `mapper`, or `undefined` if `room` is undefined. + */ +export function useRoomState(room: Room, mapper: Mapper): T; +export function useRoomState(room: Room | undefined, mapper: Mapper): T | undefined; +export function useRoomState(room: Room | undefined, mapper: Mapper): T | undefined { // Create a ref that stores mapper const savedMapper = useRef(mapper); @@ -28,7 +46,7 @@ export const useRoomState = ( savedMapper.current = mapper; }, [mapper]); - const [value, setValue] = useState(room ? mapper(room.currentState) : (undefined as T)); + const [value, setValue] = useState(room ? mapper(room.currentState) : undefined); const update = useCallback(() => { if (!room) return; @@ -39,8 +57,8 @@ export const useRoomState = ( useEffect(() => { update(); return () => { - setValue(room ? savedMapper.current(room.currentState) : (undefined as T)); + setValue(room ? savedMapper.current(room.currentState) : undefined); }; }, [room, update]); return value; -}; +}