RoomList: improve performance (#32919)

* perf: add memo to room avatar view

* perf: batch rlsV3 emit

* perf: avoid to re-render the room list if the room list state and sections are same

* perf: listen only message preview of the specific room

* perf: avoid to re-render the room list item if the notification or the content is same

* chore: replace useState and useEffect by useMemo in virtualized list

* fix: listen to room name event in RoomAvatar

* fix: room avatar re-render when room is low priority
This commit is contained in:
Florian Duros
2026-03-25 19:52:45 +00:00
committed by GitHub
parent b90a32bea4
commit 441b292353
10 changed files with 71 additions and 34 deletions
@@ -8,7 +8,7 @@
import { EventType, JoinRule, type MatrixEvent, type Room, RoomEvent } from "matrix-js-sdk/src/matrix";
import { useEffect, useState } from "react";
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import { useTypedEventEmitter, useTypedEventEmitterState } from "../../../hooks/useEventEmitter";
import { useDmMember, usePresence, type Presence } from "../../views/avatars/WithPresenceIndicator";
import { DefaultTagID } from "../../../stores/room-list-v3/skip-list/tag";
@@ -41,7 +41,7 @@ export function useRoomAvatarViewModel(room: Room): RoomAvatarViewState {
const roomMember = useDmMember(room);
const presence = usePresence(room, roomMember);
const isPublic = useIsPublic(room);
const isLowPriority = !!room.tags[DefaultTagID.LowPriority];
const isLowPriority = useTypedEventEmitterState(room, RoomEvent.Tags, () => !!room.tags[DefaultTagID.LowPriority]);
let badgeDecoration: AvatarBadgeDecoration | undefined;
if (isLowPriority) {
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { useCallback, useMemo, type ComponentProps } from "react";
import { type Room, RoomType, KnownMembership, EventType } from "matrix-js-sdk/src/matrix";
import { type Room, RoomType, KnownMembership, EventType, RoomEvent } from "matrix-js-sdk/src/matrix";
import { type RoomAvatarEventContent } from "matrix-js-sdk/src/types";
import BaseAvatar from "./BaseAvatar";
@@ -21,6 +21,7 @@ import { useSettingValue } from "../../../hooks/useSettings";
import { useRoomState } from "../../../hooks/useRoomState";
import { useRoomIdName } from "../../../hooks/room/useRoomIdName";
import { MediaPreviewValue } from "../../../@types/media_preview";
import { useTypedEventEmitterState } from "../../../hooks/useEventEmitter";
interface IProps extends Omit<ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url" | "onClick" | "size"> {
// Room may be left unset here, but if it is,
@@ -37,7 +38,8 @@ interface IProps extends Omit<ComponentProps<typeof BaseAvatar>, "name" | "idNam
}
const RoomAvatar: React.FC<IProps> = ({ room, viewAvatarOnClick, onClick, oobData, size = "36px", ...otherProps }) => {
const roomName = room?.name ?? oobData?.name ?? "?";
const name = useTypedEventEmitterState(room, RoomEvent.Name, () => room?.name);
const roomName = name ?? oobData?.name ?? "?";
const avatarEvent = useRoomState(room, (state) => state.getStateEvents(EventType.RoomAvatar, ""));
const roomIdName = useRoomIdName(room, oobData);
@@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX } from "react";
import React, { memo, type JSX } from "react";
import { type Room } from "matrix-js-sdk/src/matrix";
import PublicIcon from "@vector-im/compound-design-tokens/assets/web/icons/public";
import VideoIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call-solid";
@@ -33,7 +33,7 @@ interface RoomAvatarViewProps {
* Component to display the avatar of a room.
* Currently only 32px size is supported.
*/
export function RoomAvatarView({ room }: RoomAvatarViewProps): JSX.Element {
export const RoomAvatarView = memo(function RoomAvatarView({ room }: RoomAvatarViewProps): JSX.Element {
const vm = useRoomAvatarViewModel(room);
// No decoration, we just show the avatar
if (!vm.badgeDecoration) return <RoomAvatar size="32px" room={room} />;
@@ -54,7 +54,7 @@ export function RoomAvatarView({ room }: RoomAvatarViewProps): JSX.Element {
{label ? <Tooltip label={label}>{icon}</Tooltip> : icon}
</Flex>
);
}
});
/**
* Get the decoration for the avatar based on the presence.