perf(room): memoize timeline/composer handlers and emoji-pack room lookups
- RoomTimeline: wrap jump-to-latest/unread + mark-as-read handlers in useCallback (the handlers passed to memoized message children were already memoized). - RoomInput: wrap file/upload/emoji/sticker/location callbacks in useCallback so the editor and toolbar don't re-render needlessly. - EmojiBoard: hoist repeated mx.getRoom() pack-label lookups into a useMemo'd map in the emoji and sticker sidebars (previously called per-render in map loops). Behavior unchanged. (RoomTimeline/RoomInput already have ErrorBoundary wrappers in RoomView, so no boundary added.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -178,6 +178,16 @@ function EmojiSidebar({ activeGroupAtom, packs, onScrollToGroup }: EmojiSidebarP
|
||||
const labels = useEmojiGroupLabels();
|
||||
const icons = useEmojiGroupIcons();
|
||||
|
||||
const packLabels = useMemo(() => {
|
||||
const map = new Map<string, string | undefined>();
|
||||
packs.forEach((pack) => {
|
||||
let label = pack.meta.name;
|
||||
if (!label) label = isUserId(pack.id) ? 'Personal Pack' : mx.getRoom(pack.id)?.name;
|
||||
map.set(pack.id, label);
|
||||
});
|
||||
return map;
|
||||
}, [mx, packs]);
|
||||
|
||||
const handleScrollToGroup = (groupId: string) => {
|
||||
setActiveGroupId(groupId);
|
||||
onScrollToGroup(groupId);
|
||||
@@ -198,8 +208,7 @@ function EmojiSidebar({ activeGroupAtom, packs, onScrollToGroup }: EmojiSidebarP
|
||||
<SidebarStack>
|
||||
<SidebarDivider />
|
||||
{packs.map((pack) => {
|
||||
let label = pack.meta.name;
|
||||
if (!label) label = isUserId(pack.id) ? 'Personal Pack' : mx.getRoom(pack.id)?.name;
|
||||
const label = packLabels.get(pack.id);
|
||||
|
||||
const url =
|
||||
mxcUrlToHttp(mx, pack.getAvatarUrl(usage) ?? '', useAuthentication) ?? undefined;
|
||||
@@ -252,6 +261,16 @@ function StickerSidebar({ activeGroupAtom, packs, onScrollToGroup }: StickerSide
|
||||
const [activeGroupId, setActiveGroupId] = useAtom(activeGroupAtom);
|
||||
const usage = ImageUsage.Sticker;
|
||||
|
||||
const packLabels = useMemo(() => {
|
||||
const map = new Map<string, string | undefined>();
|
||||
packs.forEach((pack) => {
|
||||
let label = pack.meta.name;
|
||||
if (!label) label = isUserId(pack.id) ? 'Personal Pack' : mx.getRoom(pack.id)?.name;
|
||||
map.set(pack.id, label);
|
||||
});
|
||||
return map;
|
||||
}, [mx, packs]);
|
||||
|
||||
const handleScrollToGroup = (groupId: string) => {
|
||||
setActiveGroupId(groupId);
|
||||
onScrollToGroup(groupId);
|
||||
@@ -261,8 +280,7 @@ function StickerSidebar({ activeGroupAtom, packs, onScrollToGroup }: StickerSide
|
||||
<Sidebar>
|
||||
<SidebarStack>
|
||||
{packs.map((pack) => {
|
||||
let label = pack.meta.name;
|
||||
if (!label) label = isUserId(pack.id) ? 'Personal Pack' : mx.getRoom(pack.id)?.name;
|
||||
const label = packLabels.get(pack.id);
|
||||
|
||||
const url =
|
||||
mxcUrlToHttp(mx, pack.getAvatarUrl(usage) ?? '', useAuthentication) ?? undefined;
|
||||
|
||||
Reference in New Issue
Block a user