Fix failure to update room info panel on joinrule change (#31938)

* Fix failure to update room info panel on joinrule change

Currently, if the join rules are updated, the room info panel is not updated
until the panel is re-rendered. This is due to a misuse of `useRoomState`.

* Update documentation and types on `useRoomState`

This hook is useless without a `mapper` function, so let's mandate it. Also
improve the documentation while we're here.
This commit is contained in:
Richard van der Hoff
2026-02-02 16:08:03 +00:00
committed by GitHub
parent 0053bedc38
commit 7c3cf696fd
2 changed files with 31 additions and 13 deletions
@@ -158,9 +158,9 @@ export function useRoomSummaryCardViewModel(
const e2eStatus = roomContext.e2eStatus; const e2eStatus = roomContext.e2eStatus;
const isVideoRoom = calcIsVideoRoom(room); const isVideoRoom = calcIsVideoRoom(room);
const roomState = useRoomState(room); const { roomJoinRule } = useRoomState(room, (state) => ({
// used to check if the room is public or not roomJoinRule: state.getJoinRule(),
const roomJoinRule = roomState.getJoinRule(); }));
const alias = room.getCanonicalAlias() || room.getAltAliases()[0] || ""; const alias = room.getCanonicalAlias() || room.getAltAliases()[0] || "";
const pinCount = usePinnedEvents(room).length; const pinCount = usePinnedEvents(room).length;
// value to check if the user can invite to the room // value to check if the user can invite to the room
+28 -10
View File
@@ -12,14 +12,32 @@ import { type Room, type RoomState, RoomStateEvent } from "matrix-js-sdk/src/mat
import { useTypedEventEmitter } from "./useEventEmitter"; import { useTypedEventEmitter } from "./useEventEmitter";
type Mapper<T> = (roomState: RoomState) => T; type Mapper<T> = (roomState: RoomState) => T;
const defaultMapper: Mapper<RoomState> = (roomState: RoomState) => roomState;
// Hook to simplify watching Matrix Room state /**
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint * A hook to watch the state of a room.
export const useRoomState = <T extends any = RoomState>( *
room?: Room, * Call `useRoomState` in a component to watch the state of a room.
mapper: Mapper<T> = defaultMapper as Mapper<T>, *
): T => { * 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<T>(room: Room, mapper: Mapper<T>): T;
export function useRoomState<T>(room: Room | undefined, mapper: Mapper<T>): T | undefined;
export function useRoomState<T>(room: Room | undefined, mapper: Mapper<T>): T | undefined {
// Create a ref that stores mapper // Create a ref that stores mapper
const savedMapper = useRef(mapper); const savedMapper = useRef(mapper);
@@ -28,7 +46,7 @@ export const useRoomState = <T extends any = RoomState>(
savedMapper.current = mapper; savedMapper.current = mapper;
}, [mapper]); }, [mapper]);
const [value, setValue] = useState<T>(room ? mapper(room.currentState) : (undefined as T)); const [value, setValue] = useState<T | undefined>(room ? mapper(room.currentState) : undefined);
const update = useCallback(() => { const update = useCallback(() => {
if (!room) return; if (!room) return;
@@ -39,8 +57,8 @@ export const useRoomState = <T extends any = RoomState>(
useEffect(() => { useEffect(() => {
update(); update();
return () => { return () => {
setValue(room ? savedMapper.current(room.currentState) : (undefined as T)); setValue(room ? savedMapper.current(room.currentState) : undefined);
}; };
}, [room, update]); }, [room, update]);
return value; return value;
}; }